owen-it/laravel-auditing
Track and review changes to your Eloquent models with minimal setup. Laravel Auditing stores a history of updates, helps spot discrepancies or suspicious activity, and makes it easy to retrieve and display audit records in your Laravel app.
Installation:
composer require owen-it/laravel-auditing
Publish the migration and config:
php artisan vendor:publish --provider="OwenIt\Auditing\AuditingServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="OwenIt\Auditing\AuditingServiceProvider" --tag="config"
Run the migration:
php artisan migrate
Enable Auditing for a Model:
Use the Auditable trait in your Eloquent model:
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
use OwenIt\Auditing\Traits\Auditable;
class User extends Model implements AuditableContract
{
use Auditable;
}
First Use Case: Trigger an update on a model to generate an audit log:
$user = User::find(1);
$user->name = 'Updated Name';
$user->save(); // Audit log created automatically
Retrieve Audit Logs:
$audits = $user->audits; // Collection of Audit models
$audits->each(function ($audit) {
echo $audit->created_at->diffForHumans();
echo $audit->getOldValues()->toJson();
});
class Post extends Model implements AuditableContract
{
use Auditable;
}
getAuditEvents() to specify which events to audit:
public function getAuditEvents()
{
return ['created', 'updated', 'deleted'];
}
config/auditing.php:
'exclude' => [
'password',
'api_token',
],
protected $auditExclude = ['secret_key'];
config/auditing.php:
'user_resolver' => \OwenIt\Auditing\Resolvers\UserResolver::class,
OwenIt\Auditing\Contracts\Resolver:
class CustomResolver implements Resolver
{
public function resolve()
{
return request()->ip();
}
}
Register in config:
'resolvers' => [
'ip' => \App\Resolvers\CustomResolver::class,
],
$user->audits()->where('event', 'updated')->get();
$user->audits()->whereHas('changes', function ($query) {
$query->where('key', 'name');
})->get();
config/auditing.php:
'multi_user' => true,
setAuditUser() manually:
$user->setAuditUser($adminUser);
$user->name = 'Updated by Admin';
$user->save();
$user->auditTag('admin_action');
$user->name = 'Updated';
$user->save();
$user->audits()->where('tags', 'like', '%admin_action%')->get();
Automatically tag audits for admin actions:
class AdminAuditMiddleware
{
public function handle($request, Closure $next)
{
if (auth()->user()->isAdmin()) {
$request->auditTag = 'admin_action';
}
return $next($request);
}
}
Use in AppServiceProvider:
public function boot()
{
$this->app['request']->offsetSet('auditTag', null);
}
Extend OwenIt\Auditing\Contracts\AuditDriver for custom storage (e.g., Redis):
class RedisAuditDriver implements AuditDriver
{
public function log($model, $event, $changes, $old, $new, $user)
{
Redis::publish('audit', json_encode(compact('model', 'event', 'changes', 'old', 'new', 'user')));
}
}
Register in config/auditing.php:
'driver' => \App\Drivers\RedisAuditDriver::class,
Use Laravel Echo to broadcast audit events:
class AuditBroadcaster
{
public function handle($audit)
{
broadcast(new AuditEvent($audit))->toOthers();
}
}
Attach to the audited event:
event(new Audited($audit));
Log API changes with request details:
class ApiAuditResolver implements Resolver
{
public function resolve()
{
return [
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'route' => request()->route()->getName(),
];
}
}
Register in config:
'resolvers' => [
'api' => \App\Resolvers\ApiAuditResolver::class,
],
Exclude deleted_at from audits:
protected $auditExclude = ['deleted_at'];
Or globally:
'exclude' => ['deleted_at'],
auditingEnabled() to toggle dynamically:
if (!$this->auditingEnabled()) {
return;
}
protected $auditExclude = ['posts'];
resolveChanges() to customize how changes are serialized.updated_at conflicts with audit timestamps.updated_at is not excluded from audits (it’s included by default).getAuditAttributes() to customize audit fields:
public function getAuditAttributes()
{
return array_merge(parent::getAuditAttributes(), ['custom_field']);
}
try {
$user = $this->userResolver->resolve();
} catch (\Exception $e) {
$user = null;
}
'resolvers' => [
'user' => [
'enabled' => env('AUDIT_USER_RESOLVER', true),
'class' => \OwenIt\Auditing\Resolvers\UserResolver::class,
],
],
protected $auditExclude = ['password', 'remember_token'];
fillable and guarded to control what gets audited.MorphMap is properly configured in AppServiceProvider:
public function boot()
{
$this->app['router']->morphMap = [
'post' => \App\Models\Post::class,
// ...
];
}
How can I help you explore Laravel packages today?