Configuration

Configure AuditTrailBundle

Create config/packages/audit_trail.yaml and configure only the features your application needs. The database transport is the default baseline.

4.x YAML examples Transport-aware defaults

Baseline Config

# config/packages/audit_trail.yaml
audit_trail:
    enabled: true
    table_prefix: ''
    table_suffix: ''
    timezone: 'UTC'
    ignored_properties: ['updatedAt', 'updated_at']
    ignored_entities: []
    retention_days: 365
    track_ip_address: true
    track_user_agent: true
    enable_hard_delete: true
    enable_soft_delete: true
    soft_delete_field: 'deletedAt'
    cache_pool: null
    audited_methods: ['GET']
    collection_serialization_mode: 'lazy'
    max_collection_items: 100
  • table_prefix and table_suffix may contain only letters, numbers, and underscores, and cannot start with a digit.
  • soft_delete_field should be a nullable timestamp-like field, such as deletedAt or archivedAt.
  • Use mapped entity classes in ignored_entities; the bundle resolves proxies and lazy subclasses back to the mapped class.
  • Set cache_pool to a PSR-6 pool when access-audit cooldowns must survive beyond the current request.

Collection And Queue Limits

audit_trail:
    collection_serialization_mode: 'lazy' # lazy, ids_only, or eager
    max_collection_items: 100
    queue_limits:
        scheduled_audits: 1000
        pending_audit_plans: 1000
        pending_deletions: 1000

Keep collection_serialization_mode on lazy unless your audit history must include relation item IDs. Use ids_only or eager deliberately on entities where the extra Doctrine work is acceptable.

If a collection exceeds max_collection_items, the stored value is truncated to a marker payload with _truncated, _total_count, and _sample keys instead of writing an unbounded relation snapshot.

Database Transport

audit_trail:
    transports:
        database:
            enabled: true
            async: false

Use synchronous database transport when you want local persistence with no extra package. Use async: true only after installing and configuring Symfony Messenger.

Queue Transport

# config/packages/audit_trail.yaml
audit_trail:
    transports:
        queue:
            enabled: true
            bus: 'messenger.bus.default'
            # Optional: adds an ApiKeyStamp to queued audit messages.
            api_key: '%env(AUDIT_QUEUE_API_KEY)%'
# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            audit_trail: '%env(MESSENGER_TRANSPORT_DSN)%'

HTTP Transport

audit_trail:
    transports:
        http:
            enabled: true
            endpoint: 'https://audit-service.internal/api/logs'
            headers:
                Authorization: 'Bearer %env(AUDIT_HTTP_TOKEN)%'
            timeout: 10

The HTTP endpoint must start with http:// or https://. Plain HTTP is allowed only in the dev environment; use HTTPS in production. Install symfony/http-client before enabling this transport.

Integrity Signing

audit_trail:
    integrity:
        enabled: true
        secret: '%env(string:AUDIT_INTEGRITY_SECRET)%'
        algorithm: 'sha256'

When integrity is enabled, stored audit logs can be verified later and HTTP or queue payloads are signed for transport authenticity. The bundle expects the secret to be configured as a Symfony env placeholder.

EasyAdmin Options

audit_trail:
    easyadmin:
        permission: 'ROLE_ADMIN'
        export_limit: 50000

The EasyAdmin export limit keeps browser-triggered downloads bounded. Use audit:export for larger or full-history exports.

In 4.1+, the old root-level admin_permission and admin_export_limit options are deprecated. Use the nested easyadmin options shown above.

Transaction Safety

audit_trail:
    defer_transport_until_commit: true
    fail_on_transport_error: false
    fallback_to_database: true
Goal Useful Settings
Default write performance defer_transport_until_commit: true
Strict database audit path database.async: false and fail_on_transport_error: true
External transport with local safety net fallback_to_database: true with database transport enabled

HTTP and queue transports are deferred-phase transports. Setting defer_transport_until_commit: false does not move them into Doctrine's onFlush transaction window.

When HTTP or queue transport is enabled and these flags are not set explicitly, the bundle treats remote delivery as strict by default: fail_on_transport_error becomes true and fallback_to_database becomes false. Set both values deliberately for your durability model.

  • At least one transport must be enabled when audit_trail.enabled is true.
  • Enabling async database or queue transport without symfony/messenger throws a clear container-build LogicException.
  • Enabling HTTP transport without symfony/http-client throws a clear container-build LogicException.
  • Boolean or status-based soft-delete markers need custom restore handling; the built-in restore flow clears a nullable timestamp-like field.