Search by

enadstack / laravel-action-logger

Enadabuzaid

A powerful, flexible Action Logger / Audit Log package for Laravel with multi-tenancy support and optional Vue UI

Package info

github.com/Enadabuzaid/laravel-action-logger

Homepage

Issues

pkg:composer/enadstack/laravel-action-logger

Statistics

Installs: 242

Dependents: 0

Suggesters: 0

Stars: 0

v1.3.0 2026-10-30 08:53 UTC

This package is auto-updated.

Last update: 2026-11-11 12:08:59 UTC


README

Laravel Action Logger

Latest Version Total Downloads Tests License

Laravel Action Logger

A powerful, flexible, and developer-friendly Action Logger / Audit Log package for Laravel. Track all changes to your Eloquent models, support multi-tenancy out of the box, and optionally visualize logs with a beautiful Inertia + Vue 3 UI.

โœจ Features

Feature Description
๐Ÿ” Automatic CRUD Logging Log created, updated, deleted, restored events automatically
๐Ÿ“ Smart Diff Tracking Only logs changed attributes on updates
๐Ÿข Multi-Tenant Ready Column-based, request-based, or custom resolver
๐ŸŽฏ Fluent API Both direct method and fluent builder patterns
๐Ÿ”Ž Rich Query Scopes Filter by subject, actor, event, date, tenant, and more
๐ŸŽจ Optional UI Beautiful Inertia + Vue 3 + shadcn-vue dashboard
๐Ÿ”ง Highly Configurable Ignore attributes, models, events, and more
โšก Laravel 11 & 12 Full compatibility with latest Laravel versions
๐Ÿงช Fully Tested 55+ automated tests

๐Ÿ“‹ Requirements

Requirement Version
PHP 8.2 or higher
Laravel 11.0 or 12.0

๐Ÿš€ Installation

Step 1: Install via Composer

composer require enadstack/laravel-action-logger

Step 2: Run the Install Command

php artisan action-logger:install

This will:

  • โœ… Publish the configuration file
  • โœ… Publish the migration
  • โœ… Optionally run the migration
  • โœ… Display next steps

Alternative: Manual Installation

# Publish config
php artisan vendor:publish --tag=action-logger-config

# Publish migration
php artisan vendor:publish --tag=action-logger-migrations

# Run migration
php artisan migrate

๐Ÿ“– Quick Start

1. Add the Trait to Your Models

use Enadstack\ActionLogger\Traits\HasActionLogs;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasActionLogs;
}

That's it! Now all CRUD operations are automatically logged:

// Logged: created
$post = Post::create(['title' => 'My First Post']);

// Logged: updated (only changed fields)
$post->update(['title' => 'Updated Title']);

// Logged: deleted
$post->delete();

2. Query the Logs

// Get all logs for a model
$logs = $post->actionLogs;

// Get the latest log
$latestLog = $post->latestActionLog();

// Get changes from an update
if ($latestLog->isUpdated()) {
    foreach ($latestLog->getChanges() as $field => $change) {
        echo "{$field}: {$change['old']} โ†’ {$change['new']}";
    }
}

3. Log Custom Events

// Simple custom event
$post->logAction('published');

// With metadata
$post->logAction('shared', meta: [
    'platform' => 'twitter',
    'url' => 'https://...',
]);

๐Ÿ“š Documentation

Document Description
๐Ÿ“˜ Usage Guide ActionLogger service and facade usage
๐Ÿ“— Trait Documentation HasActionLogs trait complete guide
๐Ÿ“– API Reference Complete API documentation
๐Ÿ”ง Commands Artisan commands reference
๐ŸŽจ UI Guide Optional Inertia + Vue UI setup
๐Ÿ“‹ Quick Reference Cheat sheet for common tasks
๐Ÿข Multi-Tenancy Multi-tenant configuration guide
โš™๏ธ Configuration Complete configuration reference
๐Ÿ”„ Changelog Version history

๐Ÿ”ง Configuration

After installation, you can customize behavior in config/action-logger.php:

Enable/Disable Logging

// config/action-logger.php
'enabled' => env('ACTION_LOGGER_ENABLED', true),

Configure Events

'events' => [
    'created',
    'updated',
    'deleted',
    'restored',
],

Ignore Attributes

'ignore_attributes' => [
    'updated_at',
    'remember_token',
    'password',
],

Multi-Tenancy

'tenant' => [
    'mode' => 'column', // 'none', 'column', or 'resolver'
    'column' => 'tenant_id',
],

๐Ÿข Multi-Tenancy Support

The package supports three tenancy modes:

1. No Tenancy (Default)

'tenant' => [
    'mode' => 'none',
],

2. Column-Based Tenancy

Automatically reads tenant ID from your models:

'tenant' => [
    'mode' => 'column',
    'column' => 'tenant_id', // or 'provider_id', 'organization_id', etc.
],

3. Custom Resolver

Use your own logic to determine tenant context:

'tenant' => [
    'mode' => 'resolver',
    'resolver' => \App\Services\MyTenantResolver::class,
],

See Multi-Tenancy Guide for complete documentation.

Context-object tenancy

// AppServiceProvider::boot(), with action-logger.tenant.mode = 'resolver'
ActionLogger::resolveTenantUsing(fn ($subject, $actor) => TenantContext::id()); // null for platform admins

See docs/MULTI-TENANCY.md for scoping, platform_ability and action-logger:prune --tenant=<id>.

๐ŸŽจ Optional UI

The package includes a beautiful Inertia + Vue 3 + shadcn-vue UI for viewing logs.

Enable the UI

# In .env
ACTION_LOGGER_UI_ENABLED=true

Publish UI Components (Optional)

php artisan vendor:publish --tag=action-logger-ui

Access the Dashboard

Visit /action-logs to see:

  • ๐Ÿ“Š Dashboard - Statistics and recent activity
  • ๐Ÿ“‹ All Logs - Filterable, paginated log viewer
  • ๐Ÿ“ฆ Module Logs - Logs grouped by model type
  • ๐Ÿ” Record Timeline - Complete history for any record

See UI Guide for full documentation.

๐Ÿ”Ž Advanced Usage

Fluent API

use Enadstack\ActionLogger\Facades\ActionLogger;

ActionLogger::for($post)
    ->by($user)
    ->event('featured')
    ->withOld(['featured' => false])
    ->withNew(['featured' => true])
    ->addMeta('reason', 'Editor choice')
    ->save();

Custom Actor Resolution

class Order extends Model
{
    use HasActionLogs;

    protected function getActionLogActor(): ?object
    {
        return User::find($this->processed_by) ?? auth()->user();
    }
}

Conditional Logging

class Comment extends Model
{
    use HasActionLogs;

    protected function shouldLogActionEvent(string $event): bool
    {
        return !$this->is_spam;
    }
}

Rich Querying

use Enadstack\ActionLogger\Models\ActionLog;

// Combine multiple scopes
$logs = ActionLog::forSubject($post)
    ->forEvents(['created', 'updated'])
    ->recent(30)
    ->userActions()
    ->with('actor')
    ->latest()
    ->paginate(20);

// Track price changes
$priceHistory = $product->actionLogs()
    ->forEvent('updated')
    ->get()
    ->filter(fn($log) => $log->hasChangeFor('price'));

๐Ÿงพ Audit Metadata (1.1)

ActionLogger::log($subject, $actor, 'roles.assigned', null, ['role' => 'admin'], null,
    module: 'roles', severity: 'warning');            // severity: info (default) | warning | critical

ActionLogger::for($subject)->event('users.suspended')->module('users')->severity('critical')->save();

ActionLogger::log(null, null, 'permissions.synced', module: 'permissions'); // subject-less event
  • request_id is a valid X-Request-ID header ([A-Za-z0-9._\-:], 1-64 chars; invalid values are ignored), otherwise a uuid generated once per HTTP request. In console/queue/scheduler contexts without a valid header it stays null. A valid requestId: argument overrides; an invalid one is ignored.
  • Scopes: ActionLog::forModule('roles'), ::severity('warning'), ::forRequest($id).
  • Immutability: set ACTION_LOGGER_IMMUTABLE=true to make model update()/delete() throw ImmutableLogException. Bulk query-builder deletes and updates, upserts and truncate (including action-logger:prune) bypass model events and are not blocked.
  • Morph id columns (subject_id, actor_id) remain bigint.
  • Snapshot labels: subject_label / actor_label (190 chars, multibyte-safe) are stored with each entry so a deleted subject or actor still renders. They are derived from name, then email, then title, or passed explicitly: ActionLogger::log($m, $u, 'x.y', subjectLabel: 'Invoice 7', actorLabel: 'Cron'). Rows written before 1.2.0 have null labels.
  • Redaction: values of keys listed in action-logger.redact (case-insensitive, any depth) are replaced with [redacted] in old_values, new_values and meta BEFORE they are stored, so secrets never reach the table.
  • Retention under immutability: model update()/delete() throw, while action-logger:prune (bulk delete) remains the documented retention path.

๐Ÿ”จ Maintenance

Prune Old Logs

# Remove logs older than 90 days
php artisan action-logger:prune --days=90

# Preview (dry run)
php artisan action-logger:prune --days=60 --dry-run

# Prune for specific tenant
php artisan action-logger:prune --tenant=1 --days=90

View Statistics

# Stats for last 30 days
php artisan action-logger:stats

# Stats for last 7 days
php artisan action-logger:stats --days=7

Schedule Automatic Pruning

// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
    $schedule->command('action-logger:prune --days=90')
        ->weekly()
        ->sundays()
        ->at('02:00');
}

๐Ÿงช Testing

The package includes a comprehensive test suite:

# Run all tests
composer test

# Run with PHPUnit directly
vendor/bin/phpunit

# Run specific test suite
vendor/bin/phpunit --testsuite=Unit
vendor/bin/phpunit --testsuite=Feature

# Generate coverage report
vendor/bin/phpunit --coverage-html coverage

๐Ÿ’ก Examples

Check out the example files in examples/:

  • ExampleUsage.php - Service and facade usage examples
  • ExampleHasActionLogs.php - Trait usage and customization
  • ExampleCustomTenantResolver.php - Custom tenant resolver implementation

๐Ÿค Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

๐Ÿ“„ License

The MIT License (MIT). Please see LICENSE for more information.

๐Ÿ™ Credits

Made with โค๏ธ by EnadStack