tsitsishvili/elastic-audit
A Laravel package for Elasticsearch-backed audit logging. Capture Eloquent model changes and application events, store structured audit records in Elasticsearch, and search or analyze activity trails at scale with a simple, scalable setup.
tsitsishvili/elastic-audit writes your Laravel audit trail into Elasticsearch instead of a relational table — you get Kibana dashboards, full-text search over old events, and retention handled by index lifecycle management rather than DELETE queries.
Minimal path from zero to first audited event:
composer require tsitsishvili/elastic-auditphp artisan vendor:publish --tag=elastic-audit-config
Set your hosts/credentials (ELASTIC_AUDIT_HOSTS, user/password or API key) and the index name/prefix. Point it at a non-production cluster first — an audit package writing to the wrong index in prod is a bad first day.text where you wanted keyword):
php artisan list elastic
Run whichever index/mapping/health commands the package exposes, then confirm with curl localhost:9200/_cat/indices?v.User login, role change, or an Order status transition — something you'd actually want to query later ("who changed this order to refunded, and when?").GET <index>/_search or a Kibana Discover view.Where to look first: config/elastic-audit.php (the whole package's behaviour is driven from there), then the package's trait/observer entry point that you attach to models. Read the mapping definition before you write code — it dictates what you can and can't change later.
Model-driven auditing. Attach the package's trait/observer to models you want tracked, and keep the audited field list explicit rather than "all attributes". Auditing everything means every unrelated column addition silently changes your document shape, and it leaks sensitive fields (tokens, password hashes, PII) into a searchable index.
Manual, event-shaped writes. For things that aren't simple CRUD — a refund, a permission grant, a webhook received — call the audit API directly with a semantic event name (order.refunded, auth.login.failed) plus a small, stable payload. Free-form payloads are the number one cause of mapping conflicts later.
Always queue the write. Elasticsearch is a network dependency; a 300ms round-trip inside a request or inside a saving observer is a latency tax on every write. Push audit writes onto a queue worker. The trade-off is real: queued audits can be lost on worker crash or queue backlog, so pair queueing with the v4.2 failure observability work below.
Source identity (new in 4.2). Use it to distinguish where an audit originated — HTTP request, artisan command, queue job, seeder. This matters more than it sounds: without it, a nightly reconciliation job and a real user look identical in Kibana, and your "who did this" queries are wrong. Where the source is a console/job context there is no request, so expect nulls for IP/user-agent; don't build dashboards that assume those fields are always populated.
Failure observability (new in 4.2). Wire audit write failures into something you actually watch. The correct posture is: an audit failure must never break the user's request, but it must never be silent either. Route failures to your log/error tracker and, ideally, alert on sustained failure — a silently dead audit pipeline you only discover during an incident review is the classic failure mode of this whole package category.
Schema health checks (new in 4.2). Put the health-check command in your scheduler (daily is plenty) and in CI/CD after deploy. It catches mapping drift, missing indices, and cluster connectivity problems before they become a compliance gap.
Retention via ILM, not code. Define index lifecycle policy on the cluster (hot/warm/delete) rather than writing pruning logic in Laravel. Daily or monthly indices with a prefix are the standard pattern; if you need per-tenant separation, be deliberate — index-per-tenant multiplies shard count fast.
Integration tips. Inject the audit service rather than calling facades deep inside domain code, so it's swappable in tests. In tests, disable the package or point it at a fake — unit tests should not require a live cluster. For reads, use the package/Kibana for investigation and keep your operational dashboards out of the request path.
after_commit hook or an event dispatched post-commit, and accept that some audits will be missing rather than wrong-and-duplicated.QUEUE_CONNECTION=sync in dev hides every problem you'll hit in prod. Test with a real worker and kill the cluster mid-run to see what v4.2's failure observability actually tells you.text to keyword (or long to object) requires a reindex. Nail the mapping on day one and treat payload changes as schema changes — review them.composer update --dry-run before deploying — dependency conflicts here surface as confusing runtime errors, not install failures.password, token, secret, authorization, card data. An audit index is often readable by more people than your database.composer update and re-run the schema health check afterwards; nothing here implies config changes are required.How can I help you explore Laravel packages today?