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

Tomato Logs Laravel Package

tomatophp/tomato-logs

Tomato Logs gives your Laravel and TomatoPHP admin panel a simple way to browse, filter, and manage application log files from one place, so debugging production issues no longer means digging through the server filesystem.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm what the package actually does before you plan around it. The description claims an activity log viewer (create/update/delete events with user attribution), but the package name, the underlying jackiedo/laravel-log-reader dependency, and the release notes all point to a file log viewer — list storage/logs, open a file, filter by level/date/keyword, download, clear, refresh. Verify against vendor/tomatophp/tomato-logs/src/ in your pinned version before you promise a stakeholder an audit trail. If you need activity logging, that is spatie/laravel-activitylog, not this.

Prerequisites — do not skip this gate. Laravel 10/11, PHP 8.1+, Filament 3, and tomatophp/tomato-admin already installed and working. This is a Filament panel plugin; it registers a screen inside an existing panel. On a bare Laravel app it buys you a controller and a config file you still have to wire up. Off-stack, reach for opcodesio/log-viewer instead.

Install:

composer require tomatophp/tomato-logs
php artisan tomato-logs:install   # confirm signature in src/Console before assuming
# fallback if no install command in your pinned version:
php artisan vendor:publish --tag=tomato-logs-config
php artisan vendor:publish --tag=tomato-logs-assets

Register the plugin in app/Providers/Filament/AdminPanelProvider.php — confirm the exact FQCN and plugin class name in src/, the plugin API changed between Filament majors:

use TomatoPHP\TomatoLogs\TomatoLogsPlugin; // verify

public function panel(Panel $panel): Panel
{
    return $panel->plugins([
        TomatoLogsPlugin::make(),
    ]);
}

Where to look first (ten minutes, end to end): the plugin class and its register()/boot(), the config file (log path, route prefix), the page/resource class that renders the viewer, and whether any authorization gate exists. That last one is the seam you will almost certainly need to add yourself.

First use case — the loop this exists to shorten: open the admin panel, confirm the Logs entry lists storage/logs/laravel.log, trigger a 500 in staging, refresh, filter by error, read the trace. No SSH, no tail -f, no waiting on infra access. If that loop does not improve for your team, the package is not earning its dependency.

Before you go further, set the channel to daily in config/logging.php. Every workflow below is faster when "yesterday" is one discrete file rather than a scroll through a 400 MB monolith.

Implementation Patterns

Gate registration, not just the route. Assume the package ships no authorization until you have proven otherwise. Two layers, both cheap:

// 1. The menu entry never exists for non-admins
->plugins([
    ...(auth()->user()?->hasRole('admin') ? [TomatoLogsPlugin::make()] : []),
])
// 2. Route-level defense in depth — find the route name first
// php artisan route:list | grep -i log
Gate::define('viewLogs', fn (User $user) => $user->hasRole('admin'));

A low-privilege user must not see stack traces, SQL with bound parameters, or request payloads. Prove it with a test rather than a code review:

it('forbids non-admins from the log viewer', function () {
    $this->actingAs(User::factory()->create())
        ->get('/admin/logs')       // confirm actual path from route:list
        ->assertForbidden();
});

That test is your canary after every Filament/Laravel upgrade.

Point the config at what you actually write. Publish and edit the config to match config/logging.php:

return [
    'path' => storage_path('logs'),
    // 'allowed_extensions' => ['log'],
];

Day-to-day workflows worth standardizing:

  • Incident triage: current date file + error filter + search on a request ID, user email, or order number. The search box is the fastest path from "customer says checkout failed" to the guilty line.
  • Download before clear, every time. Clear is destructive and irreversible. Make it a team rule, not a judgment call.
  • Refresh before re-filtering. Refresh re-reads the file; filters apply against that read. A "stale" filter is almost always a stale read.
  • Environment separation: run it in local and staging. Do not mount it in production without redaction and a hard admin gate — and ideally not at all.
  • Non-engineers pulling logs: support staff can grab a log for a ticket without engineering. That is the concrete support-cost win.

Keep the integration thin so replacement is a deletion, not a rewrite. Last release 2024-04-29, zero dependents, no issue triage. Plan for replacement:

  • Own the menu entry and route registration yourself where feasible.
  • Do not let application code use the package's classes, view namespaces, or config keys directly — route it through your own thin wrapper.
  • If you later swap to opcodesio/log-viewer, the diff should be a plugin registration and a config file.

Pre-commit the fork trigger now. Write it down: "if this breaks on the next Laravel or Filament major, we fork under our org rather than block the upgrade." Surface area is a controller, a config, and views — roughly a day. Deciding at the moment of a blocked upgrade is what turns a small dependency into an incident.

Gotchas and Tips

The description and the code disagree. Activity-log semantics (create/update/delete, user attribution, filters by subject and date) appear nowhere in a package that reads log files. Read the source before repeating the description in a design doc.

Large files time out. The reader loads file contents into memory. A single laravel.log grown to hundreds of MB gives you a slow or failed request. Fix the cause: switch to daily, cap with LOG_MAX_FILES, and never point this at a single-file channel in production.

A blank UI is almost always filesystem permissions. If www-data cannot read storage/logs, you get an empty list rather than an error. ls -l storage/logs, confirm the FPM user can read, and check disk space — a full disk presents the same symptom.

Rotation mid-read truncates output. Cosmetic, but it looks like a corrupted stack trace during an incident. Refresh and re-read before concluding anything.

Local disk only. No S3, no CloudWatch, no Loki, no shipped streams. If your logs go off-box, this viewer reads an empty local directory and tells you nothing.

Clear has no undo. Wrap or disable that action in production. At minimum, restrict it to environments where losing the log is acceptable.

Route prefix collisions. Check php artisan route:list immediately after install; if the panel path or your app already owns that segment, adjust the panel path or the package's prefix in config.

Config changes "not taking effect" → clear caches. php artisan config:clear and view:clear before you debug a config value that seems ignored.

Filament v2 vs v3 registration differs. A mismatch is a hard blocker, not a soft degradation. Run composer why-not against your locked versions before committing to a plan.

Pin the exact version. composer require tomatophp/tomato-logs:1.1.2 — no floating constraint on an unmaintained, single-maintainer package with no security disclosure channel.

It is a developer convenience, never monitoring. No alerting, no aggregation, no retention policy, no cross-host search, no audit trail. It shortens triage in dev and staging. If someone proposes it as your observability story, correct that misread immediately.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator