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 Logger Laravel Package

minvws/audit-logger

A Laravel audit logging package that records user actions and model events into a queryable audit trail. Easily log authentication attempts, CRUD changes, and custom entries with configurable storage and a clean API for reviewing activity.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require minvws/audit-logger

The package is minvws/nl-rdo-php-audit-logger; keep the repo name handy, since the composer name and the GitHub slug differ and the README is thin.

Read src/AuditLoggerInterface.php first — as of 1.1.0 that file exists and is the contract you bind against. Before 1.1.0 there was only a concrete class, so any older snippet you find online targeting new AuditLogger(...) still works but gives you nothing to mock. Confirm the exact method signature by reading the file rather than trusting docs; the interface landed in a minor release (PR #28) with no accompanying README rewrite, so it is the authoritative source.

The first decision is not "how do I log" but "where do the records land". The package speaks PSR-3 only, so pick the sink up front: a dedicated audit log channel, syslog, or a dedicated table/stream. In Laravel, register a singleton against the interface:

// app/Providers/AuditServiceProvider.php
public function register(): void
{
    $this->app->singleton(AuditLoggerInterface::class, fn ($app) =>
        new AuditLogger($app['log']->channel('audit'))
    );
}

If your installed version predates 1.1.0 the singleton call above will fail to resolve — check composer show minvws/audit-logger and upgrade before wiring.

First use case worth wiring: a privacy-sensitive read or write — a clinician opening a patient record, an export, a permission change. That is exactly what MinVWS builds these for (NEN 7513 / GDPR accountability), and it validates the whole pipeline end-to-end in one call.

Implementation Patterns

  • Bind against AuditLoggerInterface, never the concrete class. The interface is the whole point of 1.1.0: it lets you decorate, swap in a no-op for tests, and survive a future concrete-class change. Type-hint the interface in constructors everywhere.
  • Log in the service layer, not the controller. A call in PatientRecordController@show misses console commands, queued jobs, and API routes. Log inside the action/use-case class that actually performs the operation.
  • Middleware for request-scoped context. Capture actor, IP, user agent, and a correlation ID once per request, stash it in a scoped container binding, and let the service layer pull it in. Log on success only via terminate() so failed authorizations don't produce misleading "viewed" entries.
  • Decorator over repositories. Wrap the repository or service that reads sensitive data: AuditPatientRepository implements AuditLoggerInterface (or delegates to it) and emits an event on the way through. Keeps audit concerns out of business logic and makes it trivial to swap in a no-op for tests.
  • Your own decorator to stamp common fields. Wrap AuditLoggerInterface in an AppNameAuditLogger that adds app name, environment, and tenant to every context array before delegating. One binding change, zero call-site churn.
  • Domain events → audit events in a listener. Let your domain emit PatientRecordViewed; a listener translates it into the package's event shape. Your domain never imports the audit package.
  • Observers only for boilerplate. Model observers are fine for "who changed this row" CRUD trails, but anything with legal weight (consent, disclosure, deletion) deserves an explicit, named audit event in the service layer.
  • Testing. Bind a collecting implementation of AuditLoggerInterface (or a collecting PSR-3 LoggerInterface) in the test container and assert on the event name and context array. Do not assert on formatted strings — assert on structured fields.

Gotchas and Tips

  • Upgrade to 1.1.0 for the interface. 1.0.0 has no AuditLoggerInterface; the only code change in 1.1.0 is that file (PR #28). Everything else in the release is Dependabot CI bumps — no runtime behaviour changed between 1.0.0 and 1.1.0, so there is no migration risk, only a new abstraction to adopt.
  • Pin the version. 1 star, 0 dependents, Ministry-internal origin, and a very recent 1.1.0 means no community safety net. Prefer a ^1.1 constraint — an exact 1.1.0 pin is defensible but you want the interface. The API is small enough that vendor-forking is cheap; do it if you need a patch.
  • PSR-3 context flattening. If you pass objects or nested arrays into context, many handlers cast them to Object/Array or drop them. Pre-serialize payloads with json_encode(...) before handing them to the logger.
  • No PII in the free-text message. Use identifiers and put the human-readable detail in your separate record store. Audit logs are read by people who shouldn't need to see a diagnosis to confirm an access happened.
  • Timezone. The package inherits PHP's default timezone. Set date_default_timezone_set('UTC') (or config('app.timezone')) explicitly — mixed-timezone audit trails are a compliance finding waiting to happen.
  • Event/value objects are likely immutable/readonly. Build a fresh instance per call; don't try to mutate and reuse one across a request.
  • No Laravel auto-discovery. Nothing is registered for you. A missing binding surfaces as Target [AuditLoggerInterface] is not instantiable — that's your provider, not a package bug.
  • Dedicated channel, long retention. Do not ride the default stack: daily rotation will delete records you are legally required to keep for years. Configure a separate channel with its own retention policy.
  • Decide failure semantics deliberately. Does an audit-write failure abort the operation (fail-closed) or get swallowed (fail-open)? Wrap the call in try/catch and make the choice explicit in code and in a comment — auditors will ask. Putting this in your decorator rather than at every call site is the cleanest option.
  • Debugging. Swap in a NullLogger or an in-memory logger and dump() the context array — that is faster than chasing formatted output through a handler stack.
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.
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator
manelgavalda/enrollment_mobile
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics