mrtolouei/laravel-audit

A lightweight and framework-native audit log package for Laravel applications.

Maintainers

Package info

github.com/mrtolouei/laravel-audit

pkg:composer/mrtolouei/laravel-audit

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-18 08:42 UTC

This package is auto-updated.

Last update: 2026-08-19 06:58:54 UTC


README

A lightweight, framework-native audit log package for Laravel applications.

License Tests Latest Stable Version

Laravel Audit automatically records Eloquent model changes and stores:

  • The model that was changed
  • The event that occurred
  • Original values
  • Changed values
  • The authenticated user (causer)
  • IP address
  • User agent
  • Request ID
  • Timestamp

The package is designed to stay small, explicit, and Laravel-native without requiring global observers.

Table of Contents

Requirements

  • PHP 8.2+
  • Laravel 11+
  • Laravel 12+
  • Laravel 13+

Installation

Install the package via Composer:

  composer require mrtolouei/laravel-audit

The package automatically registers its service provider through Laravel package discovery.

Publish the configuration:

  php artisan vendor:publish --tag=audit-config

Publish the migration:

  php artisan vendor:publish --tag=audit-migrations

Run the migration:

  php artisan migrate

Basic Usage

Add the Auditable trait to any Eloquent model you want to audit.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use MrTolouei\LaravelAudit\Concerns\Auditable;

class User extends Model
{
    use Auditable;
}

From this point, the following events are automatically recorded:

created
updated
deleted
restored

No observer registration is required.

How It Works

The package integrates directly with Laravel Eloquent model events through the Auditable trait.

When an auditable model triggers an event:

Eloquent Model Event
        |
        v
   Auditable Trait
        |
        v
   AuditService
        |
        +---- ChangeDetector
        |
        +---- CauserResolver
        |
        +---- AuditContext
        |
        v
   Audit Model
        |
        v
     audits table

Each audit record belongs to the changed model through a polymorphic relationship.

Audits Relationship

Every model using the Auditable trait automatically gets an audits() relationship.

$user->audits;

Get the latest audit:

$user->audits()->latest()->first();

Get all audits:

$user->audits()->latest()->get();

Audit Model

Audit records are represented by:

MrTolouei\LaravelAudit\Models\Audit

The model contains the following information:

Column Description
id Audit ID
subject_type Audited model type
subject_id Audited model ID
event Eloquent event
original_values Values before the change
changed_values Values after the change
causer_type Causer model type
causer_id Causer model ID
ip_address Request IP address
user_agent Request user agent
request_id Request/correlation ID
created_at Audit creation time
updated_at Audit update time

Audit Events

By default, all supported events are recorded:

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

You can change the global default:

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

Per-Model Events

Each model can override the global event configuration.

class User extends Model
{
    use Auditable;

    public static function getAuditEvents(): array
    {
        return [
            'created',
            'updated',
        ];
    }
}

This model will only record:

created
updated

The model-level configuration takes precedence over the global configuration.

Include / Exclude Attributes

Laravel Audit allows each model to control which attributes are recorded.

Include

Use getAuditInclude() to explicitly define the attributes that should be audited.

class User extends Model
{
    use Auditable;

    public function getAuditInclude(): array
    {
        return [
            'name',
            'email',
            'status',
        ];
    }
}

Only these attributes will be stored in the audit record.

Exclude

Use getAuditExclude() to exclude specific attributes.

class User extends Model
{
    use Auditable;

    public function getAuditExclude(): array
    {
        return [
            'password',
            'remember_token',
        ];
    }
}

Excluded attributes will not be stored in the audit record.

Include + Exclude

Both options can be used together.

class User extends Model
{
    use Auditable;

    public function getAuditInclude(): array
    {
        return [
            'name',
            'email',
            'password',
            'status',
        ];
    }

    public function getAuditExclude(): array
    {
        return [
            'password',
        ];
    }
}

The final audited attributes are:

name
email
status

Exclude is applied after include.

Change Detection

Laravel Audit records changes according to the event.

Created

For a newly created model:

[
    'original_values' => [],
    'changed_values' => [
        'name' => 'Ali',
        'email' => 'ali@example.com',
    ],
]

Updated

For an updated model:

[
    'original_values' => [
        'name' => 'Ali',
        'email' => 'old@example.com',
    ],

    'changed_values' => [
        'name' => 'Alireza',
        'email' => 'new@example.com',
    ],
]

Only changed attributes are recorded.

Deleted

For a deleted model:

[
    'original_values' => [
        'name' => 'Ali',
        'email' => 'ali@example.com',
    ],

    'changed_values' => [],
]

Restored

For a restored model, Laravel Audit records the values involved in the restoration event.

[
    'original_values' => [
        // previous values
    ],

    'changed_values' => [
        // changed values
    ],
]

Causer

The causer is the model responsible for an audit event.

By default, Laravel Audit resolves the authenticated user from Laravel's default authentication guard.

For example:

auth()->user();

If a user updates another user:

$user->update([
    'name' => 'Alireza',
]);

the audit record contains:

causer_type = App\Models\User
causer_id   = 123

The audited model and the causer are separate concepts:

subject = model being changed
causer  = model responsible for the change

Multiple Authentication Guards

Applications using multiple guards can specify which guard should be used for causer resolution.

For example:

'causer' => [
    'guard' => 'admin',
],

Laravel Audit will then resolve:

auth('admin')->user();

instead of the default guard.

For a member-based application:

'causer' => [
    'guard' => 'member',
],

Manual Causer

The CauserResolver can be used to explicitly specify the causer.

use MrTolouei\LaravelAudit\Support\CauserResolver;

$causerResolver = app(CauserResolver::class);

$causerResolver->setCauser($admin);

Subsequent audit records will use the manually specified causer.

Clear the manually configured causer:

$causerResolver->clear();

When no manual causer is configured, the resolver falls back to the configured authentication guard.

Audit Context

AuditContext stores request-related information associated with an audit.

It supports:

IP address
User agent
Request ID

During an HTTP request, the context can automatically populate itself from the current request.

$context = app(AuditContext::class);

$context->populateFromRequest();

The following values are resolved:

$request->ip();
$request->userAgent();
$request->header('X-Request-ID');

Manual Audit Context

Audit context values can also be configured manually.

use MrTolouei\LaravelAudit\Support\AuditContext;

$context = app(AuditContext::class);

$context
    ->setIpAddress('127.0.0.1')
    ->setUserAgent('My Application')
    ->setRequestId('request-123');

Manual values take precedence over values automatically resolved from the request.

For example:

$context
    ->setRequestId('custom-request-id')
    ->populateFromRequest();

The manually specified request ID will not be overwritten.

This makes the context usable outside normal HTTP requests, including:

  • Queue jobs
  • Commands
  • Scheduled tasks
  • Workers
  • Console applications
  • Background processes

Console / Queue Usage

Laravel Audit does not require an HTTP request.

For example:

$user->update([
    'status' => 'processed',
]);

inside a queue job can still create an audit record.

In such cases:

ip_address  = null
user_agent   = null
request_id   = null

unless these values are explicitly provided through AuditContext.

Testing

Run tests using PHPUnit:

  vendor/bin/phpunit

Contributing

  1. Fork the repository
  2. Create a feature branch (feature/awesome-feature)
  3. Commit your changes (git commit -m 'Add new feature')
  4. Push to the branch (git push origin feature/awesome-feature)
  5. Open a Pull Request

License

This package is open-sourced software licensed under the MIT license.