diff --git a/config/log-viewer.php b/config/log-viewer.php old mode 100644 new mode 100755 index 1e42ffb5..ee5dd4ff --- a/config/log-viewer.php +++ b/config/log-viewer.php @@ -66,9 +66,11 @@ |-------------------------------------------------------------------------- | */ + 'disable_absolute_filepaths' => env('LOG_VIEWER_DISABLE_ABSOLUTE_FILEPATHS', false), + 'filesystem' => [ - 'root' => env('LOG_VIEWER_FILESYSTEM_ROOT', ''), - 'disk' => env('LOG_VIEWER_FILESYSTEM_DISK', 'log-viewer-local'), + 'root' => env('LOG_VIEWER_FILESYSTEM_ROOT', ''), + 'disk' => env('LOG_VIEWER_FILESYSTEM_DISK', 'log-viewer-local'), ], /* diff --git a/src/Concerns/LogFile/CanCacheData.php b/src/Concerns/LogFile/CanCacheData.php index b8f2c584..388f7f73 100644 --- a/src/Concerns/LogFile/CanCacheData.php +++ b/src/Concerns/LogFile/CanCacheData.php @@ -3,7 +3,6 @@ namespace Opcodes\LogViewer\Concerns\LogFile; use Carbon\CarbonInterface; -use Illuminate\Contracts\Cache\Repository; use Opcodes\LogViewer\Facades\Cache; use Opcodes\LogViewer\Utils\GenerateCacheKey; @@ -11,7 +10,7 @@ trait CanCacheData { protected function indexCacheKeyForQuery(string $query = ''): string { - return GenerateCacheKey::for($this, md5($query) . ':index'); + return GenerateCacheKey::for($this, md5($query).':index'); } public function clearCache(): void diff --git a/src/Facades/LogViewer.php b/src/Facades/LogViewer.php index 16849940..450a822f 100644 --- a/src/Facades/LogViewer.php +++ b/src/Facades/LogViewer.php @@ -20,7 +20,7 @@ * @method static void clearFileCache() * @method static string|null getRouteDomain() * @method static array getRouteMiddleware() - * @method static Filesystem getFilesystem() + * @method static Filesystem getFilesystem($absolutePath = '') * @method static string getRoutePrefix() * @method static void auth($callback = null) * @method static void setMaxLogSize(int $bytes) diff --git a/src/Http/Livewire/FileList.php b/src/Http/Livewire/FileList.php index b3bf9c9b..68e521c1 100644 --- a/src/Http/Livewire/FileList.php +++ b/src/Http/Livewire/FileList.php @@ -90,7 +90,6 @@ public function deleteFolder(string $folderIdentifier) { $folder = LogViewer::getFolder($folderIdentifier); - if ($folder) { Gate::authorize('deleteLogFolder', $folder); diff --git a/src/LogFile.php b/src/LogFile.php old mode 100644 new mode 100755 index 23087da7..3fcb09e6 --- a/src/LogFile.php +++ b/src/LogFile.php @@ -8,7 +8,6 @@ use Opcodes\LogViewer\Exceptions\InvalidRegularExpression; use Opcodes\LogViewer\Facades\LogViewer; use Opcodes\LogViewer\Utils\Utils; -use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\StreamedResponse; class LogFile @@ -17,21 +16,33 @@ class LogFile use Concerns\LogFile\CanCacheData; public string $path; + public string $name; + public string $identifier; + + public string $absolutePath = ''; + public string $subFolder = ''; + private array $_logIndexCache; public function __construct(string $path) { + $pathInfo = pathinfo($path); $this->path = $path; - $this->name = basename($path); + $this->name = $pathInfo['basename']; $this->identifier = Str::substr(md5($path), -8, 8).'-'.$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 (str_starts_with($path, DIRECTORY_SEPARATOR)) { +// $this->absolutePath = pathinfo($path)['dirname']; +// $this->path = pathinfo($path)['basename']; +// } + $this->loadMetadata(); } @@ -51,7 +62,9 @@ public function logs(): LogReader public function size(): int { - return LogViewer::getFilesystem()->size($this->path); + return LogViewer::getFilesystem()->exists($this->path) + ? LogViewer::getFilesystem()->size($this->path) + : 0; } public function sizeInMB(): float @@ -76,7 +89,7 @@ public function downloadUrl(): string public function download(): StreamedResponse { - return LogViewer::getFilesystem()->download($this->path); + return LogViewer::getFilesystem($this->absolutePath)->download($this->path); } public function addRelatedIndex(LogIndex $logIndex): void @@ -104,13 +117,13 @@ public function getLastScannedFilePositionForQuery(?string $query = ''): ?int public function earliestTimestamp(): int { return $this->getMetadata('earliest_timestamp') - ?? LogViewer::getFilesystem()->lastModified($this->path); + ?? LogViewer::getFilesystem($this->absolutePath)->exists($this->path) ? LogViewer::getFilesystem($this->absolutePath)->lastModified($this->path) : 0; } public function latestTimestamp(): int { return $this->getMetadata('latest_timestamp') - ?? LogViewer::getFilesystem()->lastModified($this->path); + ?? LogViewer::getFilesystem($this->absolutePath)->exists($this->path) ? LogViewer::getFilesystem($this->absolutePath)->lastModified($this->path) : 0; } public function scan(int $maxBytesToScan = null, bool $force = false): void @@ -134,7 +147,9 @@ public function search(string $query = null): LogReader public function delete(): void { $this->clearCache(); - LogViewer::getFilesystem()->delete($this->path); + if (LogViewer::getFilesystem($this->absolutePath)->exists($this->path)) { + LogViewer::getFilesystem($this->absolutePath)->delete($this->path); + } LogFileDeleted::dispatch($this); } } diff --git a/src/LogFolder.php b/src/LogFolder.php index d900cf6f..37d1aa94 100644 --- a/src/LogFolder.php +++ b/src/LogFolder.php @@ -123,7 +123,7 @@ public function download(): BinaryFileResponse /** @var LogFile $file */ foreach ($this->files() as $file) { if (Gate::check('downloadLogFile', $file)) { - $zip->addFromString(name: $file->name, content: LogViewer::getFilesystem()->get($file->path)); + $zip->addFromString(name: $file->name, content: LogViewer::getFilesystem($file->absolutePath)->get($file->path)); } } diff --git a/src/LogIndex.php b/src/LogIndex.php index 3fa46ab2..46a96b7e 100644 --- a/src/LogIndex.php +++ b/src/LogIndex.php @@ -17,8 +17,11 @@ class LogIndex const DEFAULT_CHUNK_SIZE = 20_000; public string $identifier; + protected int $nextLogIndexToCreate; + protected int $lastScannedFilePosition; + protected int $lastScannedIndex; public function __construct( diff --git a/src/LogReader.php b/src/LogReader.php index 3244d992..3c0d908f 100644 --- a/src/LogReader.php +++ b/src/LogReader.php @@ -163,7 +163,7 @@ public function open(): self return $this; } - $this->fileHandle = LogViewer::getFilesystem()->readStream($this->file->path); + $this->fileHandle = LogViewer::getFilesystem($this->file->absolutePath)->readStream($this->file->path); if ($this->fileHandle === false) { throw new \Exception('Could not open "'.$this->file->path.'" for reading.'); diff --git a/src/LogViewerService.php b/src/LogViewerService.php index 28f6a503..29d75784 100755 --- a/src/LogViewerService.php +++ b/src/LogViewerService.php @@ -29,41 +29,56 @@ protected function getFilePaths(): array $baseDir = str_replace( ['[', ']'], ['{LEFTBRACKET}', '{RIGHTBRACKET}'], - str_replace('\\', '/', $this->basePathForLogs()) + str_replace('\\', '/', $this->basePathForLogs()), ); $baseDir = str_replace( - ['{LEFTBRACKET}', '{RIGHTBRACKET}'], - ['[[]', '[]]'], + ['{LEFTBRACKET}', '{RIGHTBRACKET}', '\\'], + ['[[]', '[]]', '\\\\'], $baseDir ); foreach (config('log-viewer.include_files', []) as $pattern) { + $absolute = true; if (! str_starts_with($pattern, DIRECTORY_SEPARATOR)) { $pattern = $baseDir.$pattern; + $absolute = false; } - $files = array_merge($files, $this->getFilePathsMatchingPattern($pattern)); + $files = array_merge($files, $this->getFilePathsMatchingPattern($pattern, $absolute)); } foreach (config('log-viewer.exclude_files', []) as $pattern) { + $absolute = true; if (! str_starts_with($pattern, DIRECTORY_SEPARATOR)) { $pattern = $baseDir.$pattern; + $absolute = false; } - $files = array_diff($files, $this->getFilePathsMatchingPattern($pattern)); + $files = array_diff($files, $this->getFilePathsMatchingPattern($pattern, $absolute)); } return array_values(array_reverse($files)); } - protected function getFilePathsMatchingPattern($pattern) + protected function getFilePathsMatchingPattern($pattern, $absolute = false): array { $files = []; - foreach($this->getFilesystem()->allFiles($this->basePathForLogs()) as $file) - { + if (! $absolute) { + $scannedFiles = $this->getFilesystem()->files($this->basePathForLogs()); + } else { + $pathInfo = pathinfo($pattern); + $dirname = $pathInfo['dirname']; + $pattern = $pathInfo['basename']; + + $scannedFiles = $this->getFilesystem($dirname)->files(); + } + + foreach ($scannedFiles as $file) { if (preg_match(pattern: Glob::toRegex(glob: $pattern), subject: $file)) { - $files[] = $file; + $files[] = isset($dirname) + ? $dirname.DIRECTORY_SEPARATOR.$file + : $file; } } @@ -73,8 +88,9 @@ protected function getFilePathsMatchingPattern($pattern) public function basePathForLogs(): string { $rootFolder = Str::of(config('log-viewer.filesystem.root')); - return empty($rootFolder) - ? $rootFolder->finish('/') + + return ($rootFolder != '') + ? $rootFolder->finish(DIRECTORY_SEPARATOR) : $rootFolder; } @@ -153,8 +169,17 @@ public function getRouteMiddleware(): array return config('log-viewer.middleware', []) ?: ['web']; } - public function getFilesystem(): Filesystem + public function getFilesystem($absolutePath = ''): Filesystem { + if (! config('disable_absolute_filepaths') && ($absolutePath !== '') && is_dir($absolutePath)) { + config()->set('filesystems.disks.log-viewer-absolute', [ + 'driver' => 'local', + 'root' => $absolutePath, + ]); + + return Storage::disk('log-viewer-absolute'); + } + return Storage::disk(config('log-viewer.filesystem.disk')); } diff --git a/src/LogViewerServiceProvider.php b/src/LogViewerServiceProvider.php index 160c0d02..20ccd0b8 100644 --- a/src/LogViewerServiceProvider.php +++ b/src/LogViewerServiceProvider.php @@ -23,7 +23,7 @@ public function register() $this->app['config']['filesystems.disks.log-viewer-local'] = [ 'driver' => 'local', - 'root' => storage_path('logs'), + 'root' => realpath(storage_path('logs')), ]; $this->app->bind('log-viewer', LogViewerService::class); diff --git a/src/Utils/GenerateCacheKey.php b/src/Utils/GenerateCacheKey.php index 629d5ee8..e7f278f3 100644 --- a/src/Utils/GenerateCacheKey.php +++ b/src/Utils/GenerateCacheKey.php @@ -13,19 +13,19 @@ public static function for(mixed $object, ?string $namespace = null): string $key = ''; if ($object instanceof LogFile) { - $key = self::baseKey() . ':file:' . md5($object->path); + $key = self::baseKey().':file:'.md5($object->path); } if ($object instanceof LogIndex) { - $key = self::for($object->file) . ':' . $object->identifier; + $key = self::for($object->file).':'.$object->identifier; } if (is_string($object)) { - $key = self::baseKey() . ':' . $object; + $key = self::baseKey().':'.$object; } - if (!empty($namespace)) { - $key .= ':' . $namespace; + if (! empty($namespace)) { + $key .= ':'.$namespace; } return $key; @@ -33,6 +33,6 @@ public static function for(mixed $object, ?string $namespace = null): string protected static function baseKey(): string { - return 'log-viewer:' . LogViewer::version(); + return 'log-viewer:'.LogViewer::version(); } } diff --git a/tests/Unit/GenerateCacheKeyTest.php b/tests/Unit/GenerateCacheKeyTest.php index accfac5c..ddf2927b 100644 --- a/tests/Unit/GenerateCacheKeyTest.php +++ b/tests/Unit/GenerateCacheKeyTest.php @@ -10,7 +10,7 @@ $result = GenerateCacheKey::for($file); expect($result)->toBe( - 'log-viewer:' . LogViewer::version() . ':file:' . md5($file->path) + 'log-viewer:'.LogViewer::version().':file:'.md5($file->path) ); }); @@ -20,7 +20,7 @@ $result = GenerateCacheKey::for($file, $namespace = 'randomNamespace'); expect($result)->toBe( - GenerateCacheKey::for($file) . ':' . $namespace + GenerateCacheKey::for($file).':'.$namespace ); }); @@ -30,7 +30,7 @@ $result = GenerateCacheKey::for($logIndex); expect($result)->toBe( - GenerateCacheKey::for($logIndex->file) . ':' . $logIndex->identifier + GenerateCacheKey::for($logIndex->file).':'.$logIndex->identifier ); }); @@ -39,5 +39,5 @@ $result = GenerateCacheKey::for($string); - expect($result)->toBe('log-viewer:' . LogViewer::version() . ':' . $string); + expect($result)->toBe('log-viewer:'.LogViewer::version().':'.$string); }); diff --git a/tests/Unit/LogIndex/ChunkedIndicesTest.php b/tests/Unit/LogIndex/ChunkedIndicesTest.php index 29e40c09..2f3a986c 100644 --- a/tests/Unit/LogIndex/ChunkedIndicesTest.php +++ b/tests/Unit/LogIndex/ChunkedIndicesTest.php @@ -1,7 +1,6 @@ $cacheType]);