The Problem with Audit Logs and Queued Jobs
Most Laravel audit packages handle the straightforward case well: a user updates a record, and the package logs the before and after values along with the authenticated user. The story falls apart the moment that write happens inside a queued job. The queue worker is the process that executes the Eloquent call, so a naive audit trail attributes the change to the worker—not the user who triggered the workflow two hops earlier.
Yammi Audit Log by RomaLytar solves this by carrying the original actor identity through the entire chain and attaching a correlation ID that groups every related entry—controller action, queued job, Artisan command, or scheduled task—into a single traceable workflow.
Zero Per-Model Configuration
One of Yammi's most practical qualities is that it requires no changes to your existing models. There are no traits to add, no interfaces to implement, and no observers to register. After installing the package and running the migrations, every Eloquent write is captured automatically:
composer require romalytar/yammi-audit-log-laravel
php artisan migrate
User::first()->update(['name' => 'Eric']);
// Already in the audit log — no model changes needed.
If you only want to track specific models, switch to opt-in mode in config/audit-log.php:
'capture' => ['mode' => env('AUDIT_LOG_CAPTURE_MODE', 'all')], // all | opt_in
'retention' => ['days' => env('AUDIT_LOG_RETENTION_DAYS', 180)],
'write' => ['async' => env('AUDIT_LOG_WRITE_ASYNC', false)],
One important caveat: Yammi hooks into Eloquent model events, so raw Query Builder updates bypass it and must be recorded explicitly.
Keeping the Actor Through Queued Work
This is the core differentiator. When a user dispatches a job that later modifies a model, Yammi preserves the original identity so the audit record distinguishes between:
- The executor — the process that ran the write (e.g., the queue worker)
- The initiator — the user or system that triggered the workflow
The correlation ID then links every entry belonging to the same workflow, letting you reconstruct a cascade of changes across a controller, a queued job, and a scheduled command as a single trace rather than unrelated rows. The context also records where the change ran—HTTP request, queued job, Artisan command, or scheduler.
Designed to Stay Out of the Way
The write path is built for minimal overhead. Each change produces a single insert plus a batched index of changed fields stored in a dedicated indexed table—no JSON column scanning required. Writes can be pushed to a queue to keep them off the critical path:
'write' => ['async' => env('AUDIT_LOG_WRITE_ASYNC', false)],
The capture path is also fail-open: if an audit write errors, the underlying operation still completes rather than taking the request down with it.
Optional Forensics and Compliance Features
Yammi ships several subsystems that are inactive by default:
- Integrity mode — tamper-evident hash chain to detect altered entries
- Time machine — reconstruct a record's state at any past point
- GDPR tooling — subject reports and retention handling
- Anomaly detection and SIEM streaming
- Slack and webhook alerts
- Multi-tenancy support
- Optional dashboard enabled via
php artisan audit-log:ui enable
Keeping these opt-in means the default install stays close to a plain change log.
Key Takeaways
- No traits, interfaces, or observers needed—works with existing models out of the box
- Tracks both the initiator and the executor of a change across queue hops
- Correlation IDs tie an entire workflow (request → job → command) into one trace
- Indexed field table avoids slow JSON column queries
- Fail-open write path protects application stability
- Compliance, forensics, and dashboard features are all opt-in
- Requires PHP 8.1+ and Laravel 9–13
Source: Laravel News — Yammi Audit Log