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

data-dog/audit-bundle

Doctrine ORM audit logging bundle for Symfony that records inserts, updates, diffs, and many-to-many relation changes in the same transaction as flush, links entries to the token storage user, and supports per-entity and per-field include/exclude config.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require data-dog/audit-bundle
    

    Add to config/bundles.php:

    DataDog\AuditBundle\DataDogAuditBundle::class => ['all' => true],
    
  2. Database Setup: Run migrations or schema update:

    php bin/console doctrine:migrations:diff && php bin/console doctrine:migrations:migrate
    

    (or doctrine:schema:update --force)

  3. First Audit: Perform a CRUD operation on any Doctrine entity (e.g., User):

    $user = new User();
    $user->setName('Test');
    $em->persist($user);
    $em->flush(); // Audit log auto-generated
    

Key First Use Case

Verify audit logs in the database (audit_entry table) after modifying an entity. Check fields like:

  • action (e.g., INSERT, UPDATE)
  • entity_class (e.g., App\Entity\User)
  • changes (JSON diff of modified fields)
  • user_id (if authenticated via TokenStorage)

Before going further, decide your coverage model: audits are generated for all Doctrine entities by default, so either accept that or declare your allow/deny lists up front (see audited_entities / unaudited_entities below) — retrofitting exclusions later is easier than cleaning up noise rows.


Implementation Patterns

Core Workflow

  1. Automatic Auditing:

    • All Doctrine ORM operations (persist(), merge(), remove()) trigger audits on flush().
    • No manual annotations or configuration needed for most entities.
  2. Controlling Which Entities Are Audited (v1.3.2): The bundle now honours the audited_entities and unaudited_entities configuration keys. Use an allowlist when you only care about a handful of domain entities, or a denylist when you want default-on coverage with exceptions.

    Allowlist — audit only these:

    # config/packages/data_dog_audit.yaml
    data_dog_audit:
        audited_entities:
            - 'App\Entity\User'
            - 'App\Entity\Order'
    

    Denylist — audit everything except these:

    data_dog_audit:
        unaudited_entities:
            - 'App\Entity\UnimportantEntity'
            - 'App\Entity\SessionLog'
    

    Pick one strategy per application: prefer audited_entities for large legacy schemas (a denylist is easy to get wrong and quietly audit dozens of join/log tables), and unaudited_entities for new apps where the domain is small and mostly auditable.

  3. Customizing Audit Fields: Extend the AuditEntry entity (e.g., add ip_address):

    // src/Entity/AuditEntry.php
    use DataDog\AuditBundle\Entity\AuditEntry as BaseAuditEntry;
    
    class AuditEntry extends BaseAuditEntry {
        /**
         * @ORM\Column(type="string", nullable=true)
         */
        private $ipAddress;
    }
    
  4. Linking Users to Audits: Ensure TokenStorage is configured (e.g., Symfony’s security.token_storage). The bundle auto-links the current user to audits.

  5. Querying Audits: Use Doctrine queries to filter audits:

    $audits = $em->getRepository(AuditEntry::class)
        ->findBy(['entityClass' => User::class, 'action' => 'UPDATE']);
    

Integration Tips

  • Configuration-driven coverage: keep entity lists in the bundle config rather than sprinkling @AuditIgnore-style logic through entities — it keeps the audit surface visible in one file and reviewable in PRs.
  • Transactions: Audits are inserted in the same transaction as the original operation. Rollbacks preserve data consistency.
  • Performance: For high-traffic apps, consider batching audits or using async processing (e.g., Symfony Messenger).
  • Testing: Mock AuditEntry in tests to avoid DB writes:
    $this->entityManager->getConnection()->getConfiguration()->setSQLLogger(null);
    
  • Assert coverage in tests: after switching to audited_entities, add a test that flushes a representative entity and asserts an audit_entry row exists, plus one asserting a non-audited entity produces none. This is the cheapest guard against config typos silently disabling auditing.

Gotchas and Tips

Pitfalls

  1. Config Keys Were Previously Ignored — Re-verify After Upgrading (v1.3.2):

    • Before v1.3.2, audited_entities / unaudited_entities were effectively not honoured, meaning auditing ran on everything regardless of what you had configured.
    • After upgrading, those lists are enforced. If you had them declared "just in case", you may suddenly stop recording audits you were relying on, or start getting a narrower set than expected.
    • Action: after the upgrade, diff the entity_class values present in audit_entry over a deploy window against the previous period. Gaps mean an entity is now excluded.
  2. Direct SQL/DQL Bypasses Audits:

    • The bundle only tracks Doctrine ORM operations. Raw SQL (e.g., entityManager->createNativeQuery()) or DQL UPDATE/DELETE are not audited.
    • Workaround: Use Doctrine repositories for all queries.
  3. Circular References in Diffs:

    • Complex entity relationships (e.g., bidirectional associations) may cause infinite recursion in diff generation.
    • Fix: Exclude problematic fields from auditing:
      data_dog_audit:
          entities:
              ignore_fields:
                  - 'App\Entity\Post#comments' # Skip comments collection
      
  4. User Linking Failures:

    • If TokenStorage is empty (e.g., API requests without auth), audits will lack user_id.
    • Tip: Set a default user or use middleware to inject context:
      $auditEntry->setUser($this->getAnonymousUser());
      
  5. Schema Updates:

    • If you modify AuditEntry, run migrations after disabling the bundle temporarily:
      php bin/console config:dump --env=prod | grep -v data_dog_audit
      

Debugging

  • Verify the effective entity lists: dump the resolved config to confirm your allow/deny lists are what the container sees (whitespace, wrong FQCN, or a stale cache will silently give you default full coverage):
    php bin/console debug:config data_dog_audit
    php bin/console cache:clear
    
  • Enable Logging: Set debug: true in config to log audit events to Symfony’s logger:
    data_dog_audit:
        debug: true
    
  • Check Diffs: Audit changes field may contain malformed JSON if entity getters/setters throw exceptions. Validate with:
    json_decode($auditEntry->getChanges(), true);
    

Extension Points

  1. Custom Actions: Trigger audits manually for non-ORM changes:

    $auditManager = $this->container->get('data_dog_audit.manager.audit');
    $auditManager->audit($entity, 'CUSTOM_ACTION', ['custom_data' => 'value']);
    
  2. Event Listeners: Subscribe to data_dog_audit.pre_audit or data_dog_audit.post_audit events to modify audit data:

    // src/EventListener/AuditListener.php
    public function onPreAudit(AuditEvent $event) {
        $event->getAuditEntry()->setIpAddress($this->getClientIp());
    }
    
  3. Async Processing: Offload audit writes to a queue (e.g., Symfony Messenger) to reduce transaction time:

    # config/packages/messenger.yaml
    framework:
        messenger:
            transports:
                audit: '%env(MESSENGER_TRANSPORT_DSN)%'
            routing:
                'DataDog\AuditBundle\Message\AuditMessage': audit
    
  4. Config as a Feature Flag: because the audited-entity lists are plain container config, you can bind them from env vars per environment (e.g., broader audit coverage in prod, narrow in dev for log hygiene) rather than branching application code.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel