Operations

Recover, export, verify, and consume audit logs.

Use the bundle's recovery tooling, CLI commands, and stable JSON payload shape to make audit data useful after it has been written.

4.x Revert CLI Serialization

Revert & Recovery

AuditTrailBundle can revert an entity to an earlier audited state. Use it after reviewing the history for a bad import, accidental update, mistaken delete, or failed admin action.

# Revert an entity to its state in a specific audit log
php bin/console audit:revert <audit-log-uuid>

# Add recovery context
php bin/console audit:revert <audit-log-uuid> \
    --context='{"reason":"restore customer address","ticket":"SUPPORT-1234"}'

# Preview first when recovering important data
php bin/console audit:revert <audit-log-uuid> --dry-run

Revert In Code

<?php

declare(strict_types=1);

$auditReverter->revert($log, dryRun: false, force: false, context: [
    'reason' => 'restore customer address',
    'ticket_id' => 'SUPPORT-1234',
]);

By default, AuditReverter silences the normal subscriber while it writes the explicit revert audit. This avoids a duplicate technical update log. Pass silenceSubscriber: false when strict compliance or debugging requires the normal technical log too.

$auditReverter->revert(
    $log,
    dryRun: false,
    force: false,
    context: [],
    silenceSubscriber: false,
);
  • EasyAdmin shows the revert button only for the latest meaningful state-changing log.
  • The explicit revert audit points back to the original entry through reverted_log_id.
  • Soft-delete restore clears the configured nullable timestamp-like soft_delete_field.
  • Use custom revert handlers for action-specific restore logic.

Revert audits follow the same transport rules as other audit logs. In-transaction transports can roll back with the entity revert when fail_on_transport_error: true. Deferred-only transports such as HTTP and queue run only after the entity change commits successfully.

Custom Revert Handlers

Implement RevertActionHandlerInterface for action-specific restore logic. Implementations are auto-tagged when Symfony autoconfiguration is enabled, so you normally do not need to add the audit_trail.revert_action_handler tag manually.

EasyAdmin uses the same dry-run path for its revert preview. To-many relations are shown as readable collections, UUID-backed relations are previewed safely, and inverse-side collection restores synchronize owning relations so persisted reverts match the preview more reliably.

CLI Commands

List Audit Logs

php bin/console audit:list --entity=User --action=update --limit=50

Purge Old Logs

php bin/console audit:purge --before="30 days ago" --force

If integrity signing is enabled, purge verifies matching logs before deletion unless you pass --skip-integrity. The purge verification path streams matching rows instead of eager-loading large result sets.

Export Logs

php bin/console audit:export --format=json --output=audits.json

Use CLI export for large or full-history exports. EasyAdmin export applies active filters and is capped by easyadmin.export_limit.

View Diff

# By entity class and ID
php bin/console audit:diff 'App\Entity\User' 42

# Or by audit log UUID
php bin/console audit:diff <audit-log-uuid> --json

Verify Integrity

# Verify all logs
php bin/console audit:verify-integrity

# Verify one log
php bin/console audit:verify-integrity --id=<audit-log-uuid>

Useful Options

Command Options Developers Commonly Need
audit:list --entity, --entity-id, --user, --transaction, --from, --to, --details
audit:export --format=json|csv, --output, --limit, --entity, --action
audit:revert --dry-run, --force, --user, --context, --noisy
audit:purge --dry-run, --before, --force, --skip-integrity

For console-triggered audits, IP handling is conservative. The bundle prefers valid values such as AUDIT_TRAIL_CLI_IP, SSH_CLIENT, or SSH_CONNECTION; if no valid IP is available, it stores null.

Serialization

AuditLogMessageSerializer emits a flat JSON payload so queue or HTTP consumers can process audit logs outside the Symfony application.

{
  "entity_class": "App\\Entity\\User",
  "entity_id": "123",
  "action": "update",
  "old_values": { "status": "pending" },
  "new_values": { "status": "approved" },
  "changed_fields": ["status"],
  "user_id": "42",
  "username": "admin",
  "ip_address": "127.0.0.1",
  "user_agent": "Mozilla/5.0",
  "transaction_hash": "019e05e8-e794-7797-bf4f-8286f65a18cd",
  "created_at": "2024-01-20T12:00:00+00:00",
  "signature": "entity-hmac-signature-here",
  "delivery_id": null,
  "reverted_log_id": null,
  "context": { "source": "checkout" }
}

The serializer is encode-only. Consumers should treat the payload as plain JSON and read transport-level signatures from HTTP headers or Messenger stamps. Queue delivery can carry X-Audit-Api-Key and X-Audit-Signature headers when the matching stamps are present; HTTP delivery uses the X-Signature header when integrity is enabled.