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.
composer require elaborate-code/laravel-eloquent-logs — the service provider is auto-discovered; no manual registration in config/app.php.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.logs()) on audited models. That relation is what you'll reach for most of the time.php artisan tinker. One row per event, with the diff, validates config, migration and causer resolution in a single loop.composer update is enough; no re-publish and no migrate required.Log::where('loggable_type', $model->getMorphClass())->where('loggable_id', $model->getKey())->latest('id'). Order by id, not created_at; same-second writes tie.restored row plus a confusing updated row that only touched deleted_at.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.assertDatabaseHas; reach for Event::fake() only when you deliberately want to suppress logging in unrelated tests.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.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.null. Every timeline view needs a null-safe branch so a deleted loggable doesn't produce a 500.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.$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.DatabaseSeeder and test fixtures, or you'll insert tens of thousands of noise rows and slow the suite noticeably.(loggable_type, loggable_id) and on created_at if the shipped migration doesn't. History queries degrade quickly at scale without them.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.How can I help you explore Laravel packages today?