Skip to content

Commit

Permalink
make it possible to group and rename multiple file includes
Browse files Browse the repository at this point in the history
  • Loading branch information
arukompas committed Jan 10, 2025
1 parent 605d32d commit fd47bb7
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 11 deletions.
5 changes: 3 additions & 2 deletions config/log-viewer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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/*',
Expand Down
10 changes: 9 additions & 1 deletion src/LogFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
54 changes: 46 additions & 8 deletions src/LogViewerService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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)) {
Expand Down
10 changes: 10 additions & 0 deletions tests/Feature/LogViewerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
31 changes: 31 additions & 0 deletions tests/Unit/FilePathsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});

0 comments on commit fd47bb7

Please sign in to comment.