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

Laravel Eloquent Logs Laravel Package

elaborate-code/laravel-eloquent-logs

Laravel Eloquent Logs adds automatic activity logging to your Eloquent models, recording create, update, and delete events with changed attributes and the user responsible. Keep a clear audit trail of model changes with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

  • composer require elaborate-code/laravel-eloquent-logs — the service provider is auto-discovered; no manual registration in config/app.php.
  • Publish and migrate: php artisan vendor:publish to get the config (and migrations, if you want to edit the schema), then php artisan migrate. Read the shipped migration before running it — the column list tells you exactly what you'll be querying all day: event name, model type/id, changed attributes, causer, timestamps.
  • Where to look first: the published config file. It is effectively the whole API surface — which events are recorded, which models are in or out, whether attribute diffs are stored, and how the acting user is resolved. Read it before touching any model.
  • Then find the Eloquent model backing the log table and check whether the package exposes a morph relation (e.g. logs()) on audited models. That relation is what you'll reach for most of the time.
  • First use case: opt one model in, then create, update and delete a record in php artisan tinker. One row per event, with the diff, validates config, migration and causer resolution in a single loop.
  • 1.1.0 ships no schema changes — composer update is enough; no re-publish and no migrate required.

Implementation Patterns

  • Opt in per model rather than globally at the start. Auditing every model on a mature app floods the table and exposes sensitive columns before you've set up a deny-list.
  • Store diffs, not snapshots. For "who changed the price and from what", the changed-attributes payload is what you render; full snapshots on every save bloat the table fast on busy models.
  • Rendering history: eager-load the relation for detail pages, but for timeline views query the log model directly and paginate there — Log::where('loggable_type', $model->getMorphClass())->where('loggable_id', $model->getKey())->latest('id'). Order by id, not created_at; same-second writes tie.
  • Resolve the causer at write time (request context), not read time. That's what makes the trail trustworthy when support staff open a record weeks later.
  • Pair logging with soft deletes for reversible actions: the log row is the "why", the soft delete is the "undo". Since 1.1.0 the two no longer duplicate, so a restore reads as a single state change instead of a restored row plus a confusing updated row that only touched deleted_at.
  • Bulk and import paths: Model::query()->update(), insert() and upsert() fire no model events, so they produce no logs. If those paths need an audit trail, either chunk through ->each->save() (slower, correct) or write explicit entries around the batch.
  • Put cross-cutting rules ("never log during seeding", "never log while impersonating support") in one service or observer rather than scattering conditionals across models.
  • Tests: assert on the log table with assertDatabaseHas; reach for Event::fake() only when you deliberately want to suppress logging in unrelated tests.
  • Schedule retention from day one. Audit tables grow monotonically and nobody remembers to add the pruning job later.

Gotchas and Tips

  • 1.1.0 is behaviourally different even though it has no API changes: the deleted event is now ignored for soft-deleted and force-deleted models, and updated is ignored when a model is restored. Any test, dashboard counter or report that counted rows on those paths will change. Run the suite after upgrading and grep for assertions on delete/restore rows.
  • Because deleted is suppressed on both delete flavours, confirm in your own app that a force delete still leaves the audit row you actually want. If not, hook forceDeleted or log it in the calling code — the parent row is gone afterwards, so there's nothing left to reconstruct it from.
  • Force-deleted records leave orphaned history: the morph relation resolves to null. Every timeline view needs a null-safe branch so a deleted loggable doesn't produce a 500.
  • If you log the updated event on a soft-deletable model, you'll see diffs that only touch the deleted-at column. Filter those out when rendering diffs or they'll read as noise.
  • Don't audit the log model itself. Self-referential logging doubles every write at best and loops at worst.
  • $hidden and $guarded do not protect the log table. Passwords, API tokens and personal data land in changed-attributes unless you add an explicit deny-list in config or a per-model exclusion. This is the most common security finding on audit tables.
  • Transactions: log rows written inside a transaction roll back with it. Usually correct, but if you need an immutable trail (rolled-back writes, failed jobs), write after commit or to a separate connection.
  • Seeding and factories: disable logging in DatabaseSeeder and test fixtures, or you'll insert tens of thousands of noise rows and slow the suite noticeably.
  • Indexing: add composite indexes on (loggable_type, loggable_id) and on created_at if the shipped migration doesn't. History queries degrade quickly at scale without them.
  • Extension points worth knowing: swap the log model for a subclass via config when you need extra columns or scopes; customise the causer resolver if actors aren't identified by Auth::id() (multi-tenant, impersonation, API tokens); override the event-to-label mapping if the UI should show human-readable strings instead of raw event names.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin