From a86940123ace87893e99cb0c79d56c4639379984 Mon Sep 17 00:00:00 2001 From: Arunas Skirius Date: Fri, 16 Jan 2026 20:39:30 +0200 Subject: [PATCH 1/2] Expand Laravel log file detection to support flexible filenames Update isPossiblyLaravelLogFile() regex to match any laravel-*.log pattern, enabling detection of custom channel logs like laravel-mychannel.log --- src/LogTypeRegistrar.php | 2 +- tests/Unit/LogTypeRegistrarTest.php | 129 ++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/LogTypeRegistrarTest.php diff --git a/src/LogTypeRegistrar.php b/src/LogTypeRegistrar.php index 754cf243..b572cbd4 100644 --- a/src/LogTypeRegistrar.php +++ b/src/LogTypeRegistrar.php @@ -114,6 +114,6 @@ public function guessTypeFromFileName(LogFile $file): ?string protected function isPossiblyLaravelLogFile(string $fileName): bool { return $fileName === 'laravel.log' - || preg_match('/laravel-\d{4}-\d{2}-\d{2}\.log/', $fileName); + || preg_match('/^laravel-.+\.log$/', $fileName); } } diff --git a/tests/Unit/LogTypeRegistrarTest.php b/tests/Unit/LogTypeRegistrarTest.php new file mode 100644 index 00000000..9e8b9f13 --- /dev/null +++ b/tests/Unit/LogTypeRegistrarTest.php @@ -0,0 +1,129 @@ +registrar = new LogTypeRegistrar; +}); + +test('laravel.log is detected as Laravel log', function () { + $path = storage_path('logs/laravel.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::LARAVEL); +}); + +test('laravel-YYYY-MM-DD.log is detected as Laravel log', function () { + $path = storage_path('logs/laravel-2024-01-16.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::LARAVEL); +}); + +test('laravel-mychannel.log is detected as Laravel log', function () { + $path = storage_path('logs/laravel-mychannel.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::LARAVEL); +}); + +test('laravel-anything.log is detected as Laravel log', function () { + $path = storage_path('logs/laravel-anything.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::LARAVEL); +}); + +test('laravel-errors.log is detected as Laravel log', function () { + $path = storage_path('logs/laravel-errors.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::LARAVEL); +}); + +test('php-fpm.log is detected as PHP-FPM log', function () { + $path = storage_path('logs/php-fpm.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::PHP_FPM); +}); + +test('access.log is detected as HTTP access log', function () { + $path = storage_path('logs/access.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::HTTP_ACCESS); +}); + +test('postgres.log is detected as Postgres log', function () { + $path = storage_path('logs/postgres.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::POSTGRES); +}); + +test('redis.log is detected as Redis log', function () { + $path = storage_path('logs/redis.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::REDIS); +}); + +test('supervisor.log is detected as Supervisor log', function () { + $path = storage_path('logs/supervisor.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBe(LogType::SUPERVISOR); +}); + +test('unknown.log returns null', function () { + $path = storage_path('logs/unknown.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBeNull(); +}); + +test('custom.log returns null', function () { + $path = storage_path('logs/custom.log'); + file_put_contents($path, ''); + + $logFile = new LogFile($path); + $type = $this->registrar->guessTypeFromFileName($logFile); + + expect($type)->toBeNull(); +}); From f2bb53729cc19249897d648af7a44c966928e825 Mon Sep 17 00:00:00 2001 From: Arunas Skirius Date: Sat, 28 Feb 2026 08:33:44 +0200 Subject: [PATCH 2/2] Fix tests failing on Windows due to locked file handles --- src/Concerns/LogReader/KeepsInstances.php | 10 ++++ tests/Pest.php | 3 ++ tests/Unit/LogTypeRegistrarTest.php | 61 +++++------------------ 3 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/Concerns/LogReader/KeepsInstances.php b/src/Concerns/LogReader/KeepsInstances.php index 5ebc31ce..8e4760e1 100644 --- a/src/Concerns/LogReader/KeepsInstances.php +++ b/src/Concerns/LogReader/KeepsInstances.php @@ -23,12 +23,22 @@ public static function instance(LogFile $file): static public static function clearInstance(LogFile $file): void { if (isset(static::$_instances[$file->path])) { + if (method_exists(static::$_instances[$file->path], 'closeFile')) { + static::$_instances[$file->path]->closeFile(); + } + unset(static::$_instances[$file->path]); } } public static function clearInstances(): void { + foreach (static::$_instances as $instance) { + if (method_exists($instance, 'closeFile')) { + $instance->closeFile(); + } + } + static::$_instances = []; } } diff --git a/tests/Pest.php b/tests/Pest.php index a89d8a9b..3664fe4d 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -79,6 +79,9 @@ function dummyLogData(?int $lines = null, string $type = LogType::LARAVEL): stri function clearGeneratedLogFiles(): void { + $logReaderClass = \Opcodes\LogViewer\Facades\LogViewer::logReaderClass(); + $logReaderClass::clearInstances(); + File::cleanDirectory(storage_path('logs')); clearstatcache(); } diff --git a/tests/Unit/LogTypeRegistrarTest.php b/tests/Unit/LogTypeRegistrarTest.php index 9e8b9f13..351ce4f1 100644 --- a/tests/Unit/LogTypeRegistrarTest.php +++ b/tests/Unit/LogTypeRegistrarTest.php @@ -1,6 +1,5 @@ registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::LARAVEL); }); test('laravel-YYYY-MM-DD.log is detected as Laravel log', function () { - $path = storage_path('logs/laravel-2024-01-16.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('laravel-2024-01-16.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::LARAVEL); }); test('laravel-mychannel.log is detected as Laravel log', function () { - $path = storage_path('logs/laravel-mychannel.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('laravel-mychannel.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::LARAVEL); }); test('laravel-anything.log is detected as Laravel log', function () { - $path = storage_path('logs/laravel-anything.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('laravel-anything.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::LARAVEL); }); test('laravel-errors.log is detected as Laravel log', function () { - $path = storage_path('logs/laravel-errors.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('laravel-errors.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::LARAVEL); }); test('php-fpm.log is detected as PHP-FPM log', function () { - $path = storage_path('logs/php-fpm.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('php-fpm.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::PHP_FPM); }); test('access.log is detected as HTTP access log', function () { - $path = storage_path('logs/access.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('access.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::HTTP_ACCESS); }); test('postgres.log is detected as Postgres log', function () { - $path = storage_path('logs/postgres.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('postgres.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::POSTGRES); }); test('redis.log is detected as Redis log', function () { - $path = storage_path('logs/redis.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('redis.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::REDIS); }); test('supervisor.log is detected as Supervisor log', function () { - $path = storage_path('logs/supervisor.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('supervisor.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBe(LogType::SUPERVISOR); }); test('unknown.log returns null', function () { - $path = storage_path('logs/unknown.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('unknown.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBeNull(); }); test('custom.log returns null', function () { - $path = storage_path('logs/custom.log'); - file_put_contents($path, ''); - - $logFile = new LogFile($path); + $logFile = generateLogFile('custom.log'); $type = $this->registrar->guessTypeFromFileName($logFile); expect($type)->toBeNull();