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

Action Logger Bundle Laravel Package

gepur-it/action-logger-bundle

A Symfony bundle for logging user and system actions into a structured audit trail. It helps capture activity and events with configurable logging, making it easier to review history, debug issues, and support compliance requirements.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it's a Symfony bundle, not a Laravel package. gepur-it/action-logger-bundle ships a DependencyInjection/ extension, a Configuration.php tree, service tags, and Doctrine ORM wiring — none of which Laravel's container understands. For a Laravel codebase, treat it as a reference implementation of an audit-trail design, not a dependency. composer require gepur-it/action-logger-bundle in a Laravel app will install fine and do absolutely nothing.

Where to look first, in this order:

  1. src/DependencyInjection/Configuration.php — the full set of knobs (table name, enabled listeners, ignored entities/fields). This is your spec.
  2. src/Entity/ActionLog* — the schema. This is the part you'll actually port to an Eloquent migration.
  3. src/Service/*Logger* or similar — the write path. Note whether it flushes immediately or defers.
  4. src/EventListener/ / src/EventSubscriber/ — how it hooks Doctrine lifecycle events and/or the kernel.
  5. README.md + composer.json require block — confirm the Symfony/PHP/Doctrine version floor before assuming anything compiles.

If you are genuinely in a Symfony app: register the bundle in config/bundles.php, import its config in config/packages/, then run bin/console doctrine:schema:update --dump-sql (the bundle almost certainly does not ship migrations — it expects you to generate them from the entity mapping).

The correct first use case is the smallest one: log one thing manually. Resolve the logger service in a controller, call it once with an explicit payload, confirm the row lands where you expect. Only after that works should you enable any auto-listener — auto-capture is where this class of package gets dangerous.

Implementation Patterns

Manual call at the service boundary. The pattern that ages best is injecting the logger into your own domain services and calling it explicitly after a business operation succeeds. Explicit calls survive refactors, schema changes, and framework upgrades; auto-listeners do not. Use the bundle's automatic capture for the long tail of CRUD you don't want to hand-instrument, not for anything you'd page someone about.

Doctrine lifecycle listener for auto-capture. The usual shape is onFlush to harvest the UnitOfWork's getScheduledEntityInsertions/Updates/Deletions and computed change sets, then persist log rows in postFlush (or re-schedule via the UoW) so you don't recurse. The change set is the valuable artifact — it gives you old/new per field without serializing whole entities.

Request-level listener for non-entity actions. A kernel kernel.request/kernel.response pair captures logins, exports, API calls, and anything that touches no entity. Pair it with a correlation/request ID so a single user gesture that spans several log rows is reconstructible.

Ported to Laravel, the mapping is:

Bundle concept Laravel equivalent
Doctrine onFlush listener Eloquent model observer (created/updated/deleted)
Kernel event listener HTTP middleware + terminate()
Logger service Singleton AuditLogger in the container
ActionLog entity action_logs migration + ActionLog model
Bundle config tree config/audit.php

Keep the schema shape: id, occurred_at, actor_id (+ actor_type if you have multiple guards), action (verb), subject_type, subject_id, changes (JSON), ip, user_agent, request_id, context (JSON). Index (subject_type, subject_id, occurred_at) and (actor_id, occurred_at) — audit tables are read by subject and by actor, never by primary key.

Decouple the write from the transaction when the volume is real. An audit row inside the business transaction means an audit-table lock in your critical path and a failed audit write rolls back a legitimate business change. Push rows onto a queue, or at minimum write to a separate connection. The counterargument — you must never lose an audit record — argues for the same transaction. Pick one deliberately; don't inherit the bundle's default by accident.

Redact at write time, not read time. Filter password, remember_token, api_token, card fields, and anything named *_secret in the change-set harvester. A leaked audit table is a credential dump.

Gotchas and Tips

Assume it does not run on modern Symfony. Last release was January 2021 (Symfony 4/5 era). Expect breakage on Symfony 6/7 and Doctrine DBAL 3+: EntityManagerInterface typed properties, removed getEntityManager() on listeners, array-vs-Configuration container APIs, and method signature return types. With one star and zero dependents, nobody has hit these before you. If you use it at all, fork and vendor it — composer require against an abandoned branch is a supply-chain and breakage risk with no upside.

Infinite-flush recursion. The classic failure: persisting an ActionLog from inside onFlush re-triggers onFlush. The Configuration usually exposes an ignored-entities list — put the log entity in it — but verify, because a missing guard shows up as a stack overflow under load, not in dev.

Never persist the entity into the log. Serializing the managed entity captures proxies, lazy collections, and circular references, and Doctrine's json type will either blow up or store 4MB of noise. Store the change set plus IDs only.

Flush timing is the subtell. If the bundle logs in onFlush and your code later throws, you have audit rows for changes that never committed. If it logs in postFlush, a failure there is silent. Read the actual listener; don't infer it from the README.

Check what it registers implicitly. Some audit bundles auto-register routes, dashboard controllers, or a kernel.exception listener. bin/console debug:router and debug:container --tag=... before you ship — surprise routes in production are a bad day.

Proxy-aware client IP. If it calls $request->getClientIp() without trusted_proxies configured, every row behind a load balancer logs the balancer's IP. Fix in framework.trusted_proxies, not in the bundle.

Extension points are your escape hatch. In Symfony, override the logger service by ID in services.yaml or decorate it; the Configuration tree's class parameter (if present) lets you swap the entity. In a Laravel port, bind an interface in a service provider and never reference the concrete class — you will want to swap the storage backend within six months.

Volume planning. Audit tables grow without bound and are rarely pruned. Decide retention (90 days? 2 years? permanent for compliance?) and partitioning before the table has 40M rows. Writing the policy down now is cheaper than the migration later.

Debugging a missing log entry. In order: (1) is the listener registered — debug:event-dispatcher; (2) is the entity in the ignore list; (3) did the operation actually flush a change (no-op updates produce empty change sets); (4) did an exception in the logger get swallowed. A silent try/catch around the log write is the single most common cause of "the audit trail has holes."

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect