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

Audit Log Laravel Package

wedevelopnl/audit-log

A Laravel package for recording audit trails of your application's data. It logs model events such as create, update, and delete, capturing the changes made, the user responsible, and timestamps, so you can review activity and keep a reliable history of modifications to your Eloquent models.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and migrate. composer require wedevelopnl/audit-log, publish the config and migrations (php artisan vendor:publish), then php artisan migrate. The 6.0.0 schema adds indexes on channel, actor_label and subject_label, so existing installs must run the new migrations — don't skip them or reader queries will table-scan.

  2. Where to look first. Read the config file for the default channel and the flush strategy, then skim docs/adr/0010-records-commit-with-the-callers-flush.md — it defines the flush contract that the entire 6.0.0 error-logging behaviour hangs off.

  3. First use case. Record a meaningful business event (e.g. "invoice marked paid") with a subject model and actor, then read it back through RecordReader:

    audit()->record(new InvoicePaid($invoice));
    app(RecordReader::class)->forSubject($invoice)->latest()->get();
    

    Verify the record appears after a normal request and after a queued job — that confirms flushing is wired to both kernel.terminate and console.terminate.

Implementation Patterns

  • Explicit record + deferred flush. Records accumulate during a request/job and are persisted on the caller's flush (end of request or console command). Treat recording as a side effect and never assume a record hits the DB mid-request.
  • Wrap writes you need atomic with the audit. Because flush rolls back with the audited change, record inside the same transaction as the domain write; the flush is the commit point.
  • Read models via RecordReader. Centralise queries there rather than hitting the record table directly — it owns the channel / actor_label / subject_label filters and now benefits from the new indexes.
  • Attach detached entries with AuditEntry::fromRecord($record) when you need to serialise or hand off an audit entry (e.g. queue payloads, notifications) without a live model reference.
  • Custom labelling. Swap the SubjectLabeller binding when the default label isn't useful for your domain. Note NullSubjectLabeller now lives in Recording, but alias resolution is unchanged, so most apps need no edits.
  • Actor labels. RecordReader::actors() now labels each actor by their most recent record, not the lexicographically greatest label — useful for "last known name" displays, but means renaming a user retroactively changes their historical actor label in that list.

Gotchas and Tips

  • Records after the last flush are reported, not silent. 6.0.0 logs an error on kernel.terminate / console.terminate when records were recorded but never flushed. If you see those errors, you're recording after the flush point (e.g. in destructors, finally blocks, or queued terminated callbacks) — move the record earlier or flush explicitly.
  • Invalid JSON now throws at record time, not flush time. FieldChange, RenderLine parameters, and event data reject NAN, INF, and invalid UTF-8 when built/recorded. This is a fix — previously the flush failed and rolled back your audited change — but it's a behaviour change: sanitise values (cast floats, mb_convert_encoding/json_encode guard) before constructing the event, or you'll now fail fast in your domain code.
  • Namespace move. NullSubjectLabeller moved from Infrastructure\Symfony to Recording. Only direct class references break; keep using the SubjectLabeller interface/alias in your app.
  • Index-aware querying. Sort and filter through RecordReader so your queries use the new indexes; ad-hoc where chains on unindexed columns will feel slow on large audit tables.
  • Extension points. Config for channel defaults, the SubjectLabeller container binding, and AuditEntry::fromRecord() are the intended seams — prefer them over subclassing records or reader internals.
  • Debugging flushes. If the new "unflushed records" error is noisy in tests, audit the terminal flush explicitly in your test bootstrap rather than disabling the listener.
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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr