tomatophp/filament-logger
Filament Logger adds a complete activity log viewer to your Filament admin panel. Automatically track model creates, updates, and deletions, monitor user actions, and browse, filter, and inspect every recorded change through a clean, native Filament interface. Quick to install and configure.
Architecture fit. The package is a single-purpose Filament plugin: it writes activity records (causer, subject, event, serialized properties, timestamps) and renders them as a Filament resource/page inside an existing panel. It does not introduce a service, queue worker, or external dependency, so it slots into the same request lifecycle as the admin panel itself. That is the right shape for what we'd use it for — internal "who changed what, when" visibility — and the wrong shape for anything needing tamper-evidence, streaming export, or independent failure domains. Treat it as a UI + table, not as a logging platform.
Integration feasibility. Low effort on the happy path: composer require, one install command (publishes config, publishes translations to lang_path(), runs migrations in-process), one ->plugin(FilamentLoggerPlugin::make()) line in the panel provider. The real integration work is not installation, it's the three decisions the package deliberately leaves to us: (1) which models get observed — a blanket observer turns the table into a firehose within a week; (2) what goes into properties — it is serialized and rendered in a cell, so it needs a redaction stance before first write, not after; (3) who can see the page — authorization is not on by default, and the page exposes other users' activity.
Technical risk. Ranked:
v3 branch). Five majors already crossed. Adopting means tracking an upstream major cadence in lockstep with our own framework upgrades — an ongoing tax, not a one-time install. Pin explicitly (^5.0 or the v3 equivalent) and commit the lockfile.TRUNCATE failure, a double-registered email-verification listener, an eager-loaded causer (N+1), and Livewire 4 request noise — but a better-tested product risk is still a product risk. Bus factor is a genuine planning input.updated events will happily serialize password hashes, tokens, and PII into properties. $hidden helps but is not a policy. There is no built-in redaction, no retention, no multi-tenant isolation.spatie/laravel-activitylog. Writing both means two tables to prune and two schemas to keep aligned. Pick one per event set.Key questions before committing.
v3-branch purchase with no announced support window?spatie/laravel-activitylog anywhere? If so, which one wins for this event set?properties — attribute names only, or values with allow-listing?Stack fit. Clean, conditional on the version gate. The package assumes Laravel + Filament as the admin surface; the entire value proposition is "review activity without leaving the dashboard." If the product doesn't use Filament, or the admin panel isn't a primary operational surface, there is no fit to evaluate. Verify the gate on day zero — v5.0.0 will not boot a Filament 3 panel.
Migration path. Two directions, and both are cheap because the footprint is small:
config/filament-logger.php before writing integration code (it is the center of gravity: model/table name, logged events, request filtering) → read the published migrations for the actual schema, not the README → register the plugin on the admin panel only (two panels on the same page slug collide) → gate the page behind a policy → add retention and indexes → roll out observers model-by-model.Data backfill is not on the table. Logging starts at install. Anything before that is invisible, so if a stakeholder expects historical answers, say so up front.
Compatibility. Hard constraints: Filament 5 / Livewire 4 / Laravel 12–13 / PHP 8.2+ for v5; v3 branch otherwise. Soft constraints that bit prior users and now have fixes worth verifying rather than trusting: FilamentLogger::log() previously required REDIRECT_STATUS (silent no-writes on nginx and artisan serve — verify with a manual call before debugging anything else), and "Clear Activities" previously used TRUNCATE, which failed silently inside a MySQL transaction. Re-test both after any upgrade rather than assuming the release note covers our environment.
Sequencing. Roughly an afternoon of engineering plus a day of policy work; the ordering matters more than the effort.
src/ (facade, page/resource, request listener), the config, and the migrations. Decide DB-backed vs. file/log driver deliberately — the config supports both and the description is ambiguous about which is default in practice.php artisan migrate in the deploy pipeline over the in-process migration on any shared database.FilamentLogger::log(...), never Log::info() — anything sent to a Laravel log channel will not appear in the panel.array_keys($model->getChanges()) over values. Keep properties to scalars and identifiers. Add tenant_id and ip at the write site — Log::withContext() no longer carries into a DB row.Prunable model or nightly delete; indexes on created_at and the causer column.tinker and refresh — row present but not on the page means a read-path problem (wrong model, filter, causer resolution); row absent means a write-path problem (observer not registered, helper failing silently).Maintenance. The recurring cost is version-tracking, and it is not small: this package has crossed five majors and moves fast enough (Filament 5 / Livewire 4 churn) that forking means hand-merging on every release. Budget it as a line item against our framework upgrade cadence. Extension points in order of safety: config → FilamentLogger::log() calls in our own observers → a custom Filament page subclass → fork (avoid). Secondary maintenance: keeping the event set curated. Every model added to the observer list is a permanent noise and volume decision.
Support. There is no vendor. MIT license, small maintainer footprint, 15 stars, no dependents — no SLA, no security response commitment, no deprecation notice. Our mitigation is the same as our integration strategy: pin the major, commit the lock, read the source, keep the footprint shallow enough to replace. The presence of a Pest suite and CI is meaningful here — it lowers the cost of our own patch if we need one — but it is not a support contract.
Scaling. Adequate for the stated envelope: internal admin panels, back-office SaaS at low-to-moderate write volume, admin edits and settings changes. It degrades in three predictable ways, all of which we can plan for:
Model::withoutEvents(...) around bulk work, one summary entry instead.TRUNCATE to DELETE is correct for MySQL transactional safety but is a row-by-row purge that degrades with table size. It is a human button, not a retention policy — size volume before relying on it.Query-side scaling is fine if the causer is eager-loaded. v5 fixed the N+1 on the table; if we replace the table or add our own causer column, we reintroduce it unless we ->with('causer') ourselves.
Failure modes. Ranked by how quietly they fail:
REDIRECT_STATUS assumption (fixed in v5) and by writing through Log::info() instead of the helper. Both produce a plausible-looking empty table rather than an error. Detection: a synthetic heartbeat write on a schedule, or a test asserting against the activities table.properties. Write-time, irreversible, and invisible until someone reads the table. Redaction policy is a pre-launch blocker, not a follow-up.TRUNCATE failed inside a MySQL transaction. Any test or wrapper asserting the table empties needs re-checking after upgrade.composer update. Unpinned, this can move us across a breaking boundary and take the panel down. Lockfile discipline is the whole mitigation.Ramp-up. Low for a Laravel-fluent engineer: the package is a config file, a helper, a page, and a listener, and the README screenshots convey the intended UX quickly. Realistic shape: half a day to install and verify on a staging panel; one to two days to configure the event set, add the policy gate and retention, and write the redaction rule; then an incremental hour per model as coverage expands. The non-engineering ramp-up — the stakeholder conversation — costs more calendar time than the code. It needs to establish, in writing, that this is an operations convenience: useful for support triage ("the invoice looked different yesterday"), incident smoke signals, and internal accountability, and explicitly not the opening move of a compliance or audit-trail program. If a regulated audit lands on the roadmap, we budget a separate, purpose-built effort and this package does not stand in for it.
How can I help you explore Laravel packages today?