Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Log Viewer Laravel Package

achyutn/filament-log-viewer

A Filament plugin that reads and displays Laravel log files in a clean, searchable table with stack traces and filtering. Register it in your panel and visit /logs to browse entries.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this package as a replacement for routine tail -f storage/logs/laravel.log inside the Filament admin panel, not as a full observability platform. The fastest path is:

  1. Confirm your Filament major version before installing:
    • Filament v5 → package ^2.x
    • Filament v4 → package ^1.x
    • Filament v3 → package ^0.x
  2. Install and publish the config.
  3. Register the plugin in the panel provider with an authorization closure.
  4. Discover the actual logs URL for your panel.
  5. Use it first for a simple error triage workflow.
composer require achyutn/filament-log-viewer
php artisan vendor:publish --tag=filament-log-viewer-config

Register it in the panel:

use AchyutN\FilamentLogViewer\FilamentLogViewer;

return $panel
    ->plugins([
        FilamentLogViewer::make()
            ->authorize(fn (): bool => auth()->user()?->can('viewLogs') ?? false)
            ->navigationGroup('System')
            ->navigationLabel('Log Viewer')
            ->navigationSort(10)
            ->pollingTime(null),
    ]);

Where to look first:

  • config/filament-log-viewer.php after publishing, especially max_log_file_size, enable_delete, truncate_on_clear, and cache settings.
  • Your panel provider, to confirm authorization and navigation placement.
  • php artisan route:list --path=logs to find the real URL. The README says /logs, but inside a Filament panel it is commonly /admin/logs or another panel-prefixed path.
  • storage/logs permissions and current log file names.

First day-to-day use case: a user reports a 500. Open the logs page, filter to the Error level and today’s date, click the view action to inspect the stack trace, then use Copy as Markdown to paste the context into a ticket or Slack thread. If the log contains mail output, the Mail tab gives a quick preview without digging through raw MIME text.

For production, start with destructive UI off:

LOG_MAX_SIZE_KB=20480
LOG_ENABLE_DELETE=false
LOG_TRUNCATE_ON_CLEAR=true
LOG_COPY_MARKDOWN_LEVELS=error,warning

Implementation Patterns

Gate access through a closure, not navigation visibility. The most common production pattern is to bind log access to a permission or role:

FilamentLogViewer::make()
    ->authorize(fn (): bool => auth()->check() && auth()->user()->can('View:LogTable'))

This works with Filament Shield or any gate/policy. Avoid ->authorize(true) outside local development; logs often contain PII, tokens, SQL, mail bodies, and internal URLs.

Scope destructive controls by environment. Keep LOG_ENABLE_DELETE=false in production. If you need clearing in staging or local, enable it there and leave truncate_on_clear=true so files remain in place with their ownership and rotation behavior intact. If you set truncate_on_clear=false, the clear action deletes files entirely; make sure your log rotation or process supervision recreates them.

Use the plugin as a triage surface, not a monitoring dependency. A practical workflow is:

  • Filter by level and date.
  • View stack traces for exceptions.
  • Copy markdown into incident notes.
  • Clear or truncate logs only after you have captured the relevant context.
  • Keep SSH/tail available for urgent production incidents, especially on multi-node deployments.

Hide the navigation item when the page should only be linked contextually. If the logs page should not appear in the sidebar, use registerNavigation(false) and link to it from a custom dashboard action or resource page. Remember that hiding navigation does not replace authorization.

FilamentLogViewer::make()
    ->registerNavigation(false)
    ->authorize(fn (): bool => auth()->user()?->is_admin ?? false);

Customize log sources by extending the provider. The default LocalLogProvider reads local log files. If you need additional files or a different storage source, swap the provider:

use AchyutN\FilamentLogViewer\Contracts\LogProvider;
use AchyutN\FilamentLogViewer\Providers\LocalLogProvider;

class AppLogProvider extends LocalLogProvider implements LogProvider
{
    protected function getAllLogFiles(): array
    {
        return ['laravel.log', 'worker.log', 'scheduler.log'];
    }
}

FilamentLogViewer::make()
    ->providerClass(AppLogProvider::class);

If you want the Clear Logs controls to remain available with a custom provider, the provider must also implement CanDeleteLogs. Otherwise the clear controls are hidden.

Swap parsers and schemas for non-standard logs. For JSON-heavy logs or custom formats, replace the parser or the relevant schema rather than post-processing in the UI:

FilamentLogViewer::make()
    ->parserClass(MyLogParser::class)
    ->errorSchemaClass(MyErrorSchema::class)
    ->jsonSchemaClass(MyJsonSchema::class);

This is also the extension point for changing how stack traces or mail entries are rendered.

Leave caching on unless you are debugging parsing. Parsed rows are cached by a fingerprint of log file name, size, and modification time, so the cache invalidates when files change. Disable it temporarily with LOG_DISABLE_CACHE=true when investigating parser behavior; do not leave it disabled permanently on busy systems.

Use polling selectively. For local/staging live-tail behavior, polling can be useful. For production, ->pollingTime(null) avoids repeated parsing and cache invalidation from an open browser tab. If you keep polling, use a conservative interval.

Prefer the contracts over the legacy Log facade. The AchyutN\FilamentLogViewer\Model\Log class still delegates to the container-resolved provider for backward compatibility, but new code should target LogProvider or a providerClass() override.

Use the Laravel Boost skill as a development aid. If Laravel Boost is installed, the package skill is discovered automatically. That is useful for asking an AI agent how to customize providers/parsers, but it is not a runtime dependency and should not be part of your production debugging path.

Gotchas and Tips

Check the Filament compatibility matrix first. The package majors track Filament majors. Installing ^2.x on Filament v4, or ^1.x on Filament v3, is the quickest way to get dependency conflicts or runtime breakage. Pin the package version that matches your Filament version and re-check after Filament upgrades.

Do not hardcode /logs. The README’s /logs is shorthand. In a Filament panel, the route is usually panel-prefixed. Use php artisan route:list --path=logs and link to the actual URL. This matters if you use registerNavigation(false) and link from a custom page.

The file-size default is documented inconsistently. The README text says the default limit is 2 MB, while the published config example uses 20480 as the fallback, which is 20 MB if the unit is KB. After publishing, inspect the resolved config value and confirm the unit via LOG_MAX_SIZE_KB. If the table looks empty for a large log file, check this limit first.

Clear logs semantics are easy to misread. Default behavior truncates file contents and keeps the file. Setting truncate_on_clear=false deletes the files. The per-file clear control only appears when more than one log file exists, and all clear controls disappear when enable_delete=false or when a custom provider does not implement CanDeleteLogs. Verify filesystem write permissions for the web user before relying on clearing from the UI.

Authorization and navigation are separate concerns. registerNavigation(false) hides the sidebar item; it does not secure the page. Always use authorize() or a panel-level access gate. Conversely, authorize(true) is fine for local development but dangerous in production.

Provider/parser overrides are application-wide, not per-panel. The plugin is registered as a container singleton. If you register it in multiple panels with different providerClass() or parserClass() values, do not expect per-panel isolation. Centralize customization in one place, or use separate applications/panels with distinct service container configurations.

Load-balanced deployments need special handling. The default provider reads local log files. Behind a load balancer, each request may hit a different node, so the logs page may show different files depending on which server handled the request. A shared cache can make this more confusing because the cache key is based on file name, size, and modification time, not hostname. For serious production use on multiple nodes, use a shared log provider or pin admin access to a specific node.

Cache invalidation is fingerprint-based, with edge cases. The cache is keyed by file name, size, and modification time, so it normally invalidates automatically. A log file rewritten within the same second to the same size could theoretically serve stale rows. If you see stale-looking entries after a log rewrite, temporarily disable the cache and re-check.

Large logs remain a browser/performance problem even under the size limit. Raising LOG_MAX_SIZE_KB to 20 MB or more may still produce slow parsing and heavy tables. Use level/date filters, rotate logs, and avoid leaving a polling tab open on a busy production log.

Date filtering can look wrong across timezones. The date picker and the log timestamps may use different timezone assumptions. If “today” shows nothing, compare the Occurred column with the raw log timestamp and check your application/logging timezone configuration.

Environment-variable lists are whitespace-sensitive. LOG_COPY_MARKDOWN_LEVELS=error, warning is not the same as error,warning after explode(','). Use no spaces unless you know the config trims values. Also rebuild config cache after changing env values: php artisan config:clear or php artisan config:cache as appropriate.

Mail preview is convenient but sensitive. The Mail tab only appears when mail messages are present, and it can expose message bodies, recipients, and headers. Treat it with the same authorization rigor as the rest of the log viewer.

Adoption is low; treat upgrades carefully. With 53 stars and zero listed dependents, this is a small package with a single-maintainer risk profile. Pin versions, test in staging, review the changelog, and keep a fallback path for critical incidents. It is a useful convenience layer, not a replacement for centralized logging or error tracking.

Debugging checklist when the page is empty or broken:

  • Confirm the plugin is registered in the correct panel provider.
  • Check the actual route with php artisan route:list --path=logs.
  • Verify storage/logs exists and the web user can read it.
  • Check max_log_file_size and whether the current log exceeds it.
  • Temporarily set LOG_DISABLE_CACHE=true.
  • Confirm the authorization closure evaluates to true for the current user.
  • Clear config cache after env changes.
  • Check the application log format against the default parser if you have customized logging.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package