enadstack / laravel-action-logger
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
pkg:composer/enadstack/laravel-action-logger
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- inertiajs/inertia-laravel: ^3
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- phpunit/phpunit: ^11.0
Suggests
- inertiajs/inertia-laravel: Required only if you enable the bundled action-logger UI (config('action-logger.ui.enabled')).
Provides
None
Conflicts
None
Replaces
None
README
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_idis a validX-Request-IDheader ([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 validrequestId:argument overrides; an invalid one is ignored.- Scopes:
ActionLog::forModule('roles'),::severity('warning'),::forRequest($id). - Immutability: set
ACTION_LOGGER_IMMUTABLE=trueto make modelupdate()/delete()throwImmutableLogException. Bulk query-builder deletes and updates, upserts and truncate (includingaction-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 fromname, thenemail, thentitle, 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]inold_values,new_valuesandmetaBEFORE they are stored, so secrets never reach the table. - Retention under immutability: model
update()/delete()throw, whileaction-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 examplesExampleHasActionLogs.php- Trait usage and customizationExampleCustomTenantResolver.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