From fd47bb721b7c5be0115402a98f6621ca421540a2 Mon Sep 17 00:00:00 2001 From: Arunas Skirius Date: Fri, 10 Jan 2025 14:01:08 +0200 Subject: [PATCH] make it possible to group and rename multiple file includes --- config/log-viewer.php | 5 +-- src/LogFile.php | 10 +++++- src/LogViewerService.php | 54 ++++++++++++++++++++++++++++----- tests/Feature/LogViewerTest.php | 10 ++++++ tests/Unit/FilePathsTest.php | 31 +++++++++++++++++++ 5 files changed, 99 insertions(+), 11 deletions(-) diff --git a/config/log-viewer.php b/config/log-viewer.php index a8646c5d..d207c3ea 100644 --- a/config/log-viewer.php +++ b/config/log-viewer.php @@ -142,8 +142,9 @@ '**/*.log', // You can include paths to other log types as well, such as apache, nginx, and more. - '/var/log/httpd/*', - '/var/log/nginx/*', + // This key => value pair can be used to rename and group multiple paths into one folder in the UI. + '/var/log/httpd/*' => 'Apache', + '/var/log/nginx/*' => 'Nginx', // MacOS Apple Silicon logs '/opt/homebrew/var/log/nginx/*', diff --git a/src/LogFile.php b/src/LogFile.php index 9e6c517e..300dbd99 100644 --- a/src/LogFile.php +++ b/src/LogFile.php @@ -21,20 +21,28 @@ class LogFile public string $name; public string $identifier; public string $subFolder = ''; + public string $displayPath; private ?string $type = null; private array $_logIndexCache; - public function __construct(string $path, ?string $type = null) + public function __construct(string $path, ?string $type = null, ?string $pathAlias = null) { $this->path = $path; $this->name = basename($path); $this->identifier = Utils::shortMd5(Utils::getLocalIP().':'.$path).'-'.$this->name; $this->type = $type; + $this->displayPath = empty($pathAlias) + ? $path + : $pathAlias . DIRECTORY_SEPARATOR . $this->name; // Let's remove the file name because we already know it. $this->subFolder = str_replace($this->name, '', $path); $this->subFolder = rtrim($this->subFolder, DIRECTORY_SEPARATOR); + if (! empty($pathAlias)) { + $this->subFolder = $pathAlias; + } + $this->loadMetadata(); } diff --git a/src/LogViewerService.php b/src/LogViewerService.php index f3c44239..e2ab35ae 100755 --- a/src/LogViewerService.php +++ b/src/LogViewerService.php @@ -61,26 +61,58 @@ protected function getLaravelLogFilePaths(): array ); } $files = []; + $filePathsCollected = []; + + foreach (config('log-viewer.include_files', []) as $pattern => $alias) { + if (is_numeric($pattern)) { + $pattern = $alias; + $alias = null; + } - foreach (config('log-viewer.include_files', []) as $pattern) { if (! str_starts_with($pattern, DIRECTORY_SEPARATOR)) { $pattern = $baseDir.$pattern; } - $files = array_merge($files, $this->getFilePathsMatchingPattern($pattern)); + $filesMatchingPattern = $this->getFilePathsMatchingPattern($pattern); + $filesMatchingPattern = array_map('realpath', $filesMatchingPattern); + $filesMatchingPattern = array_values(array_filter($filesMatchingPattern, 'is_file')); + $filesMatchingPattern = array_values(array_diff($filesMatchingPattern, $filePathsCollected)); + $filePathsCollected = array_merge($filePathsCollected, $filesMatchingPattern); + + // Let's prep aliases if they are provided. + if (! empty($alias)) { + $filesMatchingPattern = array_map(fn ($path) => [$path, $alias], $filesMatchingPattern); + } + + $files = array_merge($files, $filesMatchingPattern); } - foreach (config('log-viewer.exclude_files', []) as $pattern) { + foreach (config('log-viewer.exclude_files', []) as $pattern => $alias) { + if (is_numeric($pattern)) { + $pattern = $alias; + $alias = null; + } + if (! str_starts_with($pattern, DIRECTORY_SEPARATOR)) { $pattern = $baseDir.$pattern; } - $files = array_diff($files, $this->getFilePathsMatchingPattern($pattern)); - } + $filesMatchingPattern = $this->getFilePathsMatchingPattern($pattern); + $filesMatchingPattern = array_map('realpath', $filesMatchingPattern); + $filesMatchingPattern = array_values(array_filter($filesMatchingPattern, 'is_file')); + + if (! empty($alias)) { + $filesMatchingPattern = array_map(fn ($path) => [$path, $alias], $filesMatchingPattern); + } - $files = array_map('realpath', $files); + $files = array_filter($files, function (string|array $file) use ($filesMatchingPattern) { + if (is_array($file)) { + return ! in_array($file[0], $filesMatchingPattern); + } - $files = array_filter($files, 'is_file'); + return ! in_array($file, $filesMatchingPattern); + }); + } return array_values(array_reverse($files)); } @@ -111,7 +143,13 @@ public function getFiles(): LogFileCollection $this->_cachedFiles = (new LogFileCollection($this->getLaravelLogFilePaths())) ->unique() - ->map(fn ($filePath) => new $fileClass($filePath)) + ->map(function ($filePath) use ($fileClass) { + if (is_array($filePath)) { + [$filePath, $alias] = $filePath; + } + + return new $fileClass($filePath, null, $alias ?? null); + }) ->values(); if (config('log-viewer.hide_unknown_files', true)) { diff --git a/tests/Feature/LogViewerTest.php b/tests/Feature/LogViewerTest.php index e7cefa01..4b99f662 100644 --- a/tests/Feature/LogViewerTest.php +++ b/tests/Feature/LogViewerTest.php @@ -25,6 +25,16 @@ assertNotContains('other.log', $fileNames); }); +it('properly excludes log files added by aliased include', function () { + config()->set('log-viewer.include_files', ['*.log' => 'Alias']); + config()->set('log-viewer.exclude_files', ['*other*']); + + $fileNames = LogViewer::getFiles()->map->name; + + assertContains('laravel.log', $fileNames); + assertNotContains('other.log', $fileNames); +}); + it('hides unknown log files', function () { config()->set('log-viewer.hide_unknown_files', true); $unknownFile = generateLogFile('unknown.log', content: 'unknown log content'); diff --git a/tests/Unit/FilePathsTest.php b/tests/Unit/FilePathsTest.php index 705bc4ff..52dd18fe 100644 --- a/tests/Unit/FilePathsTest.php +++ b/tests/Unit/FilePathsTest.php @@ -108,3 +108,34 @@ ->and($files->contains('name', $second->name))->toBeFalse() ->and(file_exists($files[0]->path))->toBeTrue(); }); + +test('can set aliases for paths', function () { + config(['log-viewer.include_files' => [ + 'alias/folder/*.log' => 'TestPath', // equals to "storage/logs/alias/folder/*.log" + ]]); + $originalFile = generateLogFile('alias/folder/first.log'); + + $files = LogViewer::getFiles(); + + expect($files)->toHaveCount(1); + $file = $files[0]; + expect($file->path)->toBe($originalFile->path) + ->and($file->displayPath)->toBe('TestPath/first.log') + ->and($file->subFolder)->toBe('TestPath'); +}); + +test('shows unique files even with aliases used for paths', function () { + config(['log-viewer.include_files' => [ + 'alias/folder/*.log' => 'TestPath', // equals to "storage/logs/alias/folder/*.log" + 'alias/**/*.log', + ]]); + $originalFile = generateLogFile('alias/folder/first.log'); + + $files = LogViewer::getFiles(); + + expect($files)->toHaveCount(1); + $file = $files[0]; + expect($file->path)->toBe($originalFile->path) + ->and($file->displayPath)->toBe('TestPath/first.log') + ->and($file->subFolder)->toBe('TestPath'); +});