Transports

Choose how audits leave the app.

AuditTrailBundle can store audits in the local database, write database rows through Messenger, publish audit messages to a queue, or send JSON to an HTTP endpoint.

4.x Database Messenger HTTP

Install Matrix

Messenger is used for two different jobs: async database persistence writes local audit rows in a worker, while queue transport publishes audit messages to an external consumer. They use different message types and transport names, so both can be enabled in the same application.

Transport Extra Package Extra Symfony Config
Database None None
Async database symfony/messenger Messenger transport named audit_trail_database
Queue symfony/messenger Messenger transport named audit_trail
HTTP symfony/http-client Endpoint, headers, and timeout

Database

The database transport stores audit rows locally. During onFlush, ORM-safe rows join the current UnitOfWork. During deferred phases, the bundle writes rows without calling a nested Doctrine flush().

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

Choose synchronous database delivery when the application and audit history should stay close together and you do not want another runtime dependency.

Async Database

Async database mode sends audit rows to a Messenger worker that persists them later. This is useful when write latency matters and local database persistence is still the destination.

# config/packages/audit_trail.yaml
audit_trail:
    transports:
        database:
            enabled: true
            async: true
# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            audit_trail_database: '%env(MESSENGER_TRANSPORT_DSN)%'

Run a Messenger worker for the audit_trail_database transport in production.

php bin/console messenger:consume audit_trail_database -vv
  • Async database delivery uses an internal delivery identifier so Messenger retries are idempotent instead of creating duplicate audit rows.
  • The worker preserves the original audit-log UUID so keyset pagination and latest-first reads stay aligned with audit creation order.
  • If integrity signing is enabled, the worker verifies the carried entity signature before inserting the row.

Queue

The queue transport publishes AuditLogMessage through Symfony Messenger for an external consumer or worker pipeline. The message class is already marked with #[AsMessage(transport: 'audit_trail')]; define the matching Messenger transport.

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

Messenger Stamps

The bundle adds ApiKeyStamp when api_key is configured and SignatureStamp when integrity signing is enabled. Use AuditMessageStampEvent for application-specific Messenger stamps.

<?php

declare(strict_types=1);

namespace App\EventSubscriber;

use Rcsofttech\AuditTrailBundle\Event\AuditMessageStampEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Stamp\DelayStamp;

final class AuditMessengerSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [AuditMessageStampEvent::class => 'onAuditMessageStamp'];
    }

    public function onAuditMessageStamp(AuditMessageStampEvent $event): void
    {
        $event->addStamp(new DelayStamp(5000));
    }
}

HTTP

The HTTP transport sends audit logs to an external API endpoint, logging service, SIEM, ELK, or Splunk-style pipeline. It supports deferred phases such as postFlush and postLoad.

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

When integrity is enabled, the bundle adds an X-Signature header containing the HMAC signature of the JSON body. Plain HTTP endpoints are accepted only in the dev environment; production endpoints must use HTTPS.

Chain

The package contains chain and null transport helpers internally. For normal application config, think of chain-style delivery as enabling the destinations you want and setting failure behavior deliberately.

audit_trail:
    fallback_to_database: true
    fail_on_transport_error: false
    transports:
        database:
            enabled: true
            async: false
        http:
            enabled: true
            endpoint: 'https://audit-service.internal/api/logs'
            timeout: 5

With this shape, the external transport can be attempted while database-backed fallback remains available. Use stricter settings when a failed audit delivery should fail the application write.

  • When multiple transports are enabled, the bundle runs them in fixed order: database, then http, then queue.
  • ChainAuditTransport is fail-fast: when one child throws, later child transports do not run.
  • Fail-fast does not roll back side effects already produced by earlier transports.
  • Database-backed delivery uses internal delivery IDs for idempotency across fallback and retry paths.

Custom Transport Contract

<?php

declare(strict_types=1);

namespace App\Audit;

use Rcsofttech\AuditTrailBundle\Contract\AuditTransportInterface;
use Rcsofttech\AuditTrailBundle\Transport\AuditDeliveryResult;
use Rcsofttech\AuditTrailBundle\Transport\AuditTransportContext;

final class AppAuditTransport implements AuditTransportInterface
{
    public function send(AuditTransportContext $context): AuditDeliveryResult
    {
        // Send $context->audit to your platform.
        return AuditDeliveryResult::delivered();
    }

                    public function supports(AuditTransportContext $context): bool
    {
        return $context->phase->isAsyncDispatchPhase()
            && $context->audit->hasResolvedEntityId();
    }
}

The transport context exposes the current audit phase, entity manager, audit log, optional UnitOfWork, and source entity. Treat it as read-only. Return AuditDeliveryResult::delivered() on success, or AuditDeliveryResult::partiallyDelivered() when a multi-step transport has already completed some child deliveries before failing.