Weave Code
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

Laravel Auditable Laravel Package

ss-ipg/laravel-auditable

Attribute-based audit logging for Laravel Eloquent models. Add #[Auditable] to track create/update/delete/soft delete/restore events with old/new values, column include/exclude/redact, per-model event filters, JSON formatting, and extensible context providers.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation: Add the package via Composer:

    composer require ss-ipg/laravel-auditable
    

    Publish the config:

    php artisan vendor:publish --tag=auditable-config
    
  2. Configure Logging: Add an audit channel to config/logging.php:

    'audit' => [
        'driver' => 'daily',
        'path' => storage_path('logs/audit.log'),
        'level' => 'info',
        'days' => 14,
    ],
    
  3. Enable Auditing: Set AUDITABLE_ENABLED=true in .env and configure environments in config/auditable.php.

  4. First Use Case: Mark a model with #[Auditable] to start logging all CRUD operations:

    use SSIPG\Auditable\Attributes\Auditable;
    
    #[Auditable]
    class User extends Model {}
    

    Now, every create, update, delete, etc., on User will be logged automatically.


Implementation Patterns

Core Workflow

  1. Declarative Setup: Use #[Auditable] on models to enable auditing with zero boilerplate.

    #[Auditable(columns: ['name', 'email'], redact: ['password'])]
    class User extends Model {}
    
  2. Granular Control: Leverage attribute options for fine-tuned auditing:

    • Column Filtering: Audit only specific columns or exclude sensitive ones.
    • Event Filtering: Log only critical actions (e.g., events: [AuditAction::Deleted]).
    • Redaction: Mask sensitive fields (e.g., redact: ['api_key']).
  3. Context Enrichment: Add custom metadata via AuditContextProvider:

    class TenantContextProvider implements AuditContextProvider {
        public function getContext(Model $model, AuditAction $action): array {
            return ['tenant_id' => $model->tenant_id];
        }
    }
    

    Register in config/auditable.php:

    'context_providers' => [TenantContextProvider::class],
    
  4. Testing: Use Audit::fake() to verify auditing in tests:

    public function test_user_update_is_audited() {
        Audit::fake();
        $user = User::find(1);
        $user->update(['email' => 'new@example.com']);
        Audit::assertLogged(AuditAction::Updated);
    }
    

Integration Tips

  • Soft Deletes: Automatically detects SoftDeletes trait and logs soft_deleted/restored events.
  • Pivot Tables: Use a custom Pivot model with #[Auditable] for relationship auditing.
  • Mass Operations: Avoid using Model::update() or insert()—always use model instances for audited changes.
  • Performance: Disable auditing in non-production environments or for high-volume models via events: [].

Common Patterns

  1. Compliance Models: Audit all events for critical data:

    #[Auditable(events: [AuditAction::Created, AuditAction::Updated, AuditAction::Deleted])]
    class PatientRecord extends Model {}
    
  2. High-Volume Models: Reduce log size by excluding original values:

    #[Auditable(withOriginal: false)]
    class Comment extends Model {}
    
  3. Multi-Tenant Apps: Add tenant context to every log entry:

    class TenantContextProvider implements AuditContextProvider {
        public function getContext(Model $model, AuditAction $action): array {
            return ['tenant_id' => auth()->user()->tenant_id];
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Mass Operations Bypass Auditing:

    • Issue: Model::update(), Model::insert(), or query builder operations (e.g., DB::table()->update()) do not trigger Eloquent events.
    • Fix: Always use model instances for audited changes:
      // ✅ Audited
      $user->update(['email' => 'new@example.com']);
      
      // ❌ NOT audited
      User::where('id', 1)->update(['email' => 'new@example.com']);
      
  2. Timestamp Columns Excluded:

    • created_at, updated_at, and deleted_at are automatically excluded from change tracking (the audit log has its own timestamp).
  3. Attribute Conflicts:

    • If a model uses #[Attribute] for other purposes, ensure namespace imports are correct:
      use SSIPG\Auditable\Attributes\Auditable; // Correct
      // Avoid:
      use Attribute; // PHP 8.1+ built-in
      
  4. Soft Deletes Misconfiguration:

    • If SoftDeletes is not detected, verify the trait is properly imported:
      use Illuminate\Database\Eloquent\SoftDeletes;
      class User extends Model {
          use SoftDeletes;
      }
      

Debugging Tips

  1. Log Format Issues:

    • If logs appear malformed, check the formatter in config/auditable.php. Default is JsonFormatter, but custom formatters must implement AuditFormatter.
  2. Missing Logs:

    • Verify AUDITABLE_ENABLED=true and the environment is in config/auditable.environments.
    • Check if the log channel (audit) exists in config/logging.php.
  3. Testing Quirks:

    • Audit::fake() does not log to files—it captures entries in memory. Reset with Audit::flush() between tests.
    • Use Audit::logged() to inspect captured entries:
      $entries = Audit::logged(AuditAction::Updated);
      dd($entries);
      

Extension Points

  1. Custom Formatters:

    • Override log output by implementing AuditFormatter:
      class CustomFormatter implements AuditFormatter {
          public function format(array $payload): string {
              return "[AUDIT] " . json_encode($payload, JSON_PRETTY_PRINT);
          }
      }
      
    • Register in config/auditable.php:
      'formatter' => App\Audit\CustomFormatter::class,
      
  2. Dynamic Context:

    • Add runtime context (e.g., request ID, user agent) via a provider:
      class RequestContextProvider implements AuditContextProvider {
          public function getContext(Model $model, AuditAction $action): array {
              return [
                  'request_id' => request()->header('X-Request-ID'),
                  'user_agent' => request()->userAgent(),
              ];
          }
      }
      
  3. Event Filtering:

    • Dynamically exclude events based on model attributes:
      #[Auditable(events: fn(Model $model) => [
          AuditAction::Created,
          $model->is_audit_critical ? AuditAction::Updated : [],
      ])]
      class Product extends Model {}
      

Performance Considerations

  • Disable in Development: Set AUDITABLE_ENABLED=false in .env for local/dev environments.
  • Batch Processing: For bulk operations, disable auditing temporarily:
    config(['auditable.enabled' => false]);
    User::where(...)->update(...);
    config(['auditable.enabled' => true]);
    
  • Log Rotation: Configure audit channel in config/logging.php to manage log file size/days.

Advanced Use Cases

  1. Conditional Auditing: Use a closure for dynamic event filtering:

    #[Auditable(events: fn(Model $model) => [
        AuditAction::Created,
        $model->is_sensitive ? AuditAction::Updated : [],
    ])]
    class Document extends Model {}
    
  2. Cross-Model Auditing: Audit changes to related models via observers or model events:

    class OrderObserver {
        public function saved(Order $order) {
            if ($order->wasChanged('status')) {
                $order->auditLog()->create([...]); // Custom audit table
            }
        }
    }
    
  3. Audit Trail Queries: Query audit logs directly (if using a database driver):

    // Example: Find all updates to a user's email
    $auditLogs = AuditLog::where('model_type', User::class)
        ->where('action', AuditAction::Updated)
        ->whereJsonContains('changes->email', ['new']);
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle