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 Model Activity Log Laravel Package

foxen/laravel-model-activity-log

Automatically log Eloquent model activity in Laravel: create, update (with attribute diffs), delete, and restore (SoftDeletes). Supports per-model log names, ignoring or redacting attributes, tracks the authenticated user or falls back to “System”, and can prune old entries.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require foxen/laravel-model-activity-log
    php artisan vendor:publish --provider="Foxen\LaravelModelActivityLog\Providers\ActivityLogServiceProvider" --tag="config"
    php artisan migrate
    
    • Verify config/foxen_activitylog.php exists and adjust defaults (e.g., log_model_events, prune_old_logs) if needed.
  2. Enable Logging for a Model: Add the LogsActivity trait to your Eloquent model:

    use Foxen\LaravelModelActivityLog\Traits\LogsActivity;
    
    class Post extends Model
    {
        use LogsActivity;
        // ...
    }
    
    • No additional configuration is required for basic usage.
  3. First Use Case:

    • Create/update/delete a Post model. Check the activity_log table for entries:
      SELECT * FROM activity_log WHERE model_type = 'App\Models\Post';
      
    • Expected columns: id, model_id, model_type, action, changes, causer_id, created_at.

Implementation Patterns

Core Workflows

  1. Model-Specific Logging:

    • Exclude Attributes: Override getActivityLogAttributes() to filter sensitive fields:
      protected function getActivityLogAttributes(): array
      {
          return ['title', 'content']; // Excludes 'password' or 'api_token'
      }
      
    • Custom Actions: Extend logged actions by overriding getActivityLogEvents():
      protected function getActivityLogEvents(): array
      {
          return ['created', 'updated', 'deleted', 'published']; // Add 'published'
      }
      
  2. Causer Resolution:

    • Defaults to the authenticated user (via Auth::id()). Override getActivityLogCauser() for custom logic:
      protected function getActivityLogCauser(): ?int
      {
          return request()->user_agent === 'admin-cli' ? 1 : null;
      }
      
  3. Change Tracking:

    • For updated events, changes captures old/new values. Access via:
      $log->changes['title']['old']; // Old title value
      
  4. Pruning Old Logs:

    • Schedule a cron job (e.g., daily) to prune logs older than config('foxen_activitylog.prune_after_days'):
      php artisan activity-log:prune
      
    • Customize pruning via ActivityLogPruner service:
      $pruner = app(\Foxen\LaravelModelActivityLog\Services\ActivityLogPruner::class);
      $pruner->prune(30); // Prune logs older than 30 days
      
  5. Querying Logs:

    • Use the ActivityLog model to query logs:
      $logs = \Foxen\LaravelModelActivityLog\Models\ActivityLog::whereModelType('App\Models\Post')
          ->whereAction('updated')
          ->with('causer') // If causer is a User model
          ->get();
      

Integration Tips

  • APIs: Log API actions by resolving causer from request headers:
    protected function getActivityLogCauser(): ?int
    {
        return request()->header('X-User-ID') ? User::find(request()->header('X-User-ID'))->id : null;
    }
    
  • Admin Panels: Display logs in admin interfaces using the changes field for diff views.
  • Audit Trails: Combine with Laravel Policies to log policy violations:
    use Foxen\LaravelModelActivityLog\Traits\LogsActivity;
    
    class PostPolicy
    {
        public function delete(User $user, Post $post)
        {
            $post->logActivity('deleted', ['reason' => 'policy_violation']);
            return false;
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Performance:

    • Logging every updated event can bloat the database. Use getActivityLogEvents() to exclude frequent updates (e.g., touch() timestamps).
    • Fix: Disable logging for specific events:
      protected function getActivityLogEvents(): array
      {
          return ['created', 'updated:save', 'deleted']; // Exclude 'updated' but include 'updated:save'
      }
      
  2. Causer Resolution:

    • If Auth::id() returns null, logs will lack a causer. Ensure middleware sets the user before logging.
    • Fix: Override getActivityLogCauser() to handle anonymous actions:
      protected function getActivityLogCauser(): ?int
      {
          return Auth::check() ? Auth::id() : config('foxen_activitylog.anonymous_user_id');
      }
      
  3. Soft Deletes:

    • restored events are only logged if the model uses SoftDeletes. Forgetting to add use SoftDeletes; will miss restores.
    • Fix: Explicitly enable soft deletes and test restore flows.
  4. Change Tracking:

    • The changes field may not reflect expected values if the model uses accessors/mutators. Ensure raw attribute values are logged:
      protected function getActivityLogAttributes(): array
      {
          return array_keys($this->getAttributes());
      }
      
  5. Migration Conflicts:

    • If the activity_log table already exists, migrations may fail. Use --force or manually adjust the migration:
      php artisan migrate --force
      

Debugging

  • Missing Logs:

    • Check if the trait is correctly applied and events are not filtered out.
    • Verify the activity_log table exists and is writable.
    • Enable Laravel debugging:
      config(['foxen_activitylog.debug' => true]);
      
      Logs debug info to storage/logs/laravel.log.
  • Pruning Issues:

    • Ensure the prune_after_days config value is set and the cron job has permissions.
    • Test pruning manually:
      php artisan activity-log:prune --days=1
      

Extension Points

  1. Custom Log Models:

    • Extend the ActivityLog model to add fields (e.g., ip_address):
      class CustomActivityLog extends \Foxen\LaravelModelActivityLog\Models\ActivityLog
      {
          protected $fillable = ['ip_address'];
      }
      
    • Update the migration and trait to include new fields.
  2. Event Listeners:

    • Listen for activity.logged events to trigger side effects:
      use Foxen\LaravelModelActivityLog\Events\ActivityLogged;
      
      Event::listen(ActivityLogged::class, function (ActivityLogged $event) {
          // Send notification, update cache, etc.
      });
      
  3. Batch Logging:

    • For bulk operations (e.g., Model::update()), disable logging temporarily:
      \Foxen\LaravelModelActivityLog\Facades\ActivityLog::disableLogging();
      Post::where('published', false)->update(['published' => true]);
      \Foxen\LaravelModelActivityLog\Facades\ActivityLog::enableLogging();
      
  4. Custom Actions:

    • Log non-standard events (e.g., exported):
      $post->logActivity('exported', ['format' => 'pdf']);
      
    • Access via:
      $logs = ActivityLog::whereAction('exported')->get();
      

Config Quirks

  • log_model_events:
    • Set to false to disable logging entirely (e.g., in production for performance).
  • prune_old_logs:
    • Set to false to disable automatic pruning (use manual pruning instead).
  • anonymous_user_id:
    • Define a default user ID for anonymous actions (e.g., null or a system user ID).
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