PHPackages                             deltawhydev/laravel-audit-logging - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. deltawhydev/laravel-audit-logging

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

deltawhydev/laravel-audit-logging
=================================

Unified audit logging system for Laravel with Nova support

v1.0.0(4mo ago)0143↓57.1%MITPHPPHP ^8.2

Since Feb 20Pushed 2w agoCompare

[ Source](https://github.com/DeltaWhyDev/laravel-audit-logging)[ Packagist](https://packagist.org/packages/deltawhydev/laravel-audit-logging)[ RSS](/packages/deltawhydev-laravel-audit-logging/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (1)Dependencies (4)Versions (3)Used By (0)

Laravel Audit Log Package
=========================

[](#laravel-audit-log-package)

A robust, configurable audit logging system for Laravel applications with seamless Nova integration.

Features
--------

[](#features)

- **Automatic Logging**: easily track changes via the `Auditable` trait.
- **Transaction-aware**: logs are only committed when the database transaction succeeds.
- **Nova Integration**: includes a ready-to-use Nova Resource and a `ChangelogField` for resource detail views.
- **Highly Configurable**: customize database connections, actors, subject models, and more.
- **Formatting**: built-in support for Enums, Dates, Booleans, and Relation links.
- **Security**: strict read-only access in Nova, sensitive field masking.

Installation
------------

[](#installation)

1. Require the package via Composer:

```
composer require deltawhydev/laravel-audit-logging
```

2. Publish the configuration and migrations:

```
php artisan vendor:publish --tag=audit-log-config
php artisan vendor:publish --tag=audit-log-migrations
```

3. Run migrations:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

The `config/audit-log.php` file allows you to customize almost every aspect of the package.

### Database Connection

[](#database-connection)

You can store audit logs in a separate database (SQL or NoSQL) by setting the connection name:

```
// config/audit-log.php
'connection' => env('AUDIT_LOG_CONNECTION', 'sqlite_logs'),
```

### Namespace Customization

[](#namespace-customization)

Decouple the package from your specific app structure:

```
'model_namespace' => 'App\\Models',
'nova' => [
    'namespace' => 'App\\Nova',
    // ...
],
```

### Actor Resolution

[](#actor-resolution)

Define how the "Actor" (the user performing the action) is resolved. The package automatically retrieves the user's ID and fetches them based on this configured model, without needing to save a separate `actor_type` column:

```
'actor' => [
    'user_model' => \App\Models\User::class,
],
```

### Entity Type Resolution

[](#entity-type-resolution)

By default the package stores the `entity_type` column using the model's `getMorphClass()` value, which returns the fully qualified class name (e.g., `App\Models\User`) or its morph-map alias if one is defined globally.

There are two ways to control what value is stored:

#### Option A: Package-level `entity_type_map` (Recommended)

[](#option-a-package-level-entity_type_map-recommended)

Use this when you want short aliases **only for audit logs** without affecting the rest of your application. This is especially useful when you cannot (or don't want to) register a global `Relation::morphMap()`.

```
// config/audit-log.php
'entity_type_map' => [
    \App\Models\User::class => 'user',
    \App\Models\Pallet\Pallet::class => 'pallet',
    \App\Models\Packaging\Packaging::class => 'packaging',
],
```

The package resolves types in this order:

1. **Write** (model → alias): checks `entity_type_map` first, then falls back to `getMorphClass()`
2. **Read** (alias → model): checks `entity_type_map`, then Laravel's global morph map, then treats the value as a FQCN

This means **both old FQCN records and new alias records** resolve correctly — no data migration needed when you add the map.

#### Option B: Laravel's global `Relation::morphMap()`

[](#option-b-laravels-global-relationmorphmap)

If your application already uses a global morph map, the package respects it automatically. No additional configuration is needed — the `entity_type_map` can stay empty.

```
// AppServiceProvider::boot()
use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'user' => \App\Models\User::class,
    'product' => \App\Models\Product::class,
]);
```

> **Note:** `Relation::morphMap()` is global and affects all polymorphic columns in your application, not just audit logs. If you only want aliases in the audit log table, use Option A instead.

Usage
-----

[](#usage)

### 1. Add Trait to Models

[](#1-add-trait-to-models)

Simply add the `Auditable` trait to any Eloquent model you want to track:

```
use DeltaWhyDev\AuditLog\Traits\Auditable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use Auditable;
}
```

This will automatically log `created`, `updated`, `deleted`, and `restored` events, including changed attributes and relations (pivot events). Wait! If you are using Soft Deletes, the `deleted` event naturally triggers instead of `forceDeleted`. To capture restored events, make sure your model uses the `Illuminate\Database\Eloquent\SoftDeletes` trait.

### 2. Nova Integration

[](#2-nova-integration)

#### Audit Log Resource

[](#audit-log-resource)

Ensure `nova.resource_enabled` is set to `true` in config. The `Audit Logs` resource will appear in your Nova sidebar.

The built-in resource includes a highly-optimized **Index View** that shows a clean summary of the actor, action, and entity with clickable links, and a dedicated **Modified Fields** column that strictly lists what fields were modified without crowding the table.

**Built-In Filters:**You can easily filter your audit logs directly in Nova using the dynamic filters included in the package:

- `AuditLogActorFilter`: Dynamically populates with users who have actually performed actions, directly retrieving their configured display names.
- `AuditLogEntityFilter`: Dynamically fetches all the different Eloquent models that have been historically audited in the system.

*(These filters are already applied to the default AuditLog Nova resource, but you can also use them in your own custom lenses).*

#### Changelog Field

[](#changelog-field)

To show a history of changes directly on a resource's detail page, add the `ChangelogField`:

```
use DeltaWhyDev\AuditLog\NovaComponents\ChangelogField\ChangelogField;

public function fields(Request $request)
{
    return [
        // ... other fields

        ChangelogField::make('History')
            ->onlyOnDetail(),
    ];
}
```

The `ChangelogField` automatically handles pagination and provides a beautiful, collapsible row for every logged action. The headers cleanly show a 30-character truncated summary of what fields were changed (e.g., `Modified: status, password_hash`).

Advanced Usage
--------------

[](#advanced-usage)

### Custom Transformers

[](#custom-transformers)

You can define custom transformers to format specific field values difference:

```
// config/audit-log.php
'transformers' => [
    \App\Models\User::class => [
        'permissions' => \DeltaWhyDev\AuditLog\Transformers\JsonDiffTransformer::class,
    ],
],
```

> **Pro Tip: Custom HTML Layouts (`is_raw_html`)**If you want a transformer to take full control over its rendering (e.g. returning a raw HTML table instead of standard red/green text bubbles) without using Blade views, you can add `'is_raw_html' => true` to the array returned by your `transformDiff()` method. The `ChangelogField` frontend will output your HTML unescaped spanning the full width of the row.

### Custom View Components (Blade Templates)

[](#custom-view-components-blade-templates)

If you have complex HTML layouts that you do not want to hardcode inside your Transformer's PHP strings, you can delegate the rendering to standard Laravel Blade views. Use the `custom_views` block in the configuration file to map a key to a specific Blade template:

```
// config/audit-log.php
'custom_views' => [
    'my_custom_table' => 'audit-log.custom.my-table',
],
```

Inside your Transformer's `transformDiff()` function, skip returning `old` or `new` strings or raw html entirely. Instead, return the exact layout configuration:

```
public function transformDiff($old, $new, array $context = []): array|string|null
{
    return [
        [
            'label' => 'Entities',
            'custom_view' => config('audit-log.custom_views.my_custom_table', 'audit-log.custom.my-table'),
            'view_data' => [
                'diff' => $new, // Passing variables to the Blade view
            ],
        ],
    ];
}
```

The Changelog component will automatically parse and inject this Blade view directly into the Nova UI.

### Hidden Fields

[](#hidden-fields)

To completely hide specific attributes or relationships from the Changelog UI display, add them to the `hidden_fields` configuration array. This is especially useful for hiding technical fields like polymorphic `_type` identifiers.

```
// config/audit-log.php
'hidden_fields' => [
    \App\Models\Event\AlertReport::class => [
        'action_type', // Hides this attribute from the UI display entirely
    ],
],
```

### Search Configuration

[](#search-configuration)

By default, searching the Audit Log index is disabled to prevent performance issues on large datasets. Enable specific columns via config:

```
// config/audit-log.php
'searchable_columns' => ['entity_type', 'action'],
```

### Queueing (Async Logging)

[](#queueing-async-logging)

To prevent audit logging from slowing down your application (especially with remote databases), enable queueing:

```
// config/audit-log.php
'queue' => [
    'enabled' => true,
    'connection' => 'redis',
    'queue' => 'audit-logs',
],
```

### Pruning (Auto-Cleanup)

[](#pruning-auto-cleanup)

The package uses Laravel's `Prunable` trait to automatically delete old logs.

1. Configure retention days:

```
// config/audit-log.php
'pruning' => [
    'retention_days' => 365,
],
```

2. Schedule the pruning command in `app/Console/Kernel.php`:

```
$schedule->command('model:prune', [
    '--model' => [\DeltaWhyDev\AuditLog\Models\AuditLog::class],
])->daily();
```

### BelongsToMany Relation Tracking (`track_relations`)

[](#belongstomany-relation-tracking-track_relations)

The package can automatically log additions and removals of `BelongsToMany` relations.

#### How it works

[](#how-it-works)

There are two mechanisms for detecting pivot changes:

1. **`pivotDetached` event** — fired on `$model->relation()->detach(...)`. Logged automatically. No configuration needed.
2. **Pivot model `created`/`deleted` events** — fired when using `->using(PivotModel::class)`. The observer resolves both sides of the pivot and uses `track_relations` to decide **which parent is the owner** of the log entry.

#### Configuration

[](#configuration-1)

Add `$auditConfig` with a `track_relations` array to the owning model:

```
use DeltaWhyDev\AuditLog\Traits\Auditable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Pivot;

// The custom Pivot model (optional, needed for event-based tracking)
class OrderTag extends Pivot
{
    protected $table = 'order_tag';
}

// The owning model
class Order extends Model
{
    use Auditable;

    protected $auditConfig = [
        // List the relation method names whose changes should appear in this model's log
        'track_relations' => ['tags'],
    ];

    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'order_tag')
            ->using(OrderTag::class)
            ->withTimestamps();
    }
}

// The related model — no $auditConfig needed unless it also owns logged relations
class Tag extends Model
{
    // NOT declaring track_relations here prevents inverse duplicate logs
}
```

> **Rule:** Values in `track_relations` must exactly match the **method names** of the `belongsToMany` relations on the model (e.g. `tags`, `items`, `categories`).

#### Why `track_relations` is required for `->using()` relations

[](#why-track_relations-is-required-for--using-relations)

Without it, both sides of the pivot are treated as "owners" and the observer logs on **both** models, producing a double entry:

Without `track_relations`With `track_relations`❌ `Order` → "tags removed: Tag #5"✅ `Order` → "tags removed: Tag #5"❌ `Tag` → "orders removed: Order #12"*(skipped — not in `track_relations`)*#### Tracking multiple relations

[](#tracking-multiple-relations)

```
protected $auditConfig = [
    'track_relations' => ['tags', 'categories', 'assignees'],
];
```

#### Inheritance

[](#inheritance)

A base model's `$auditConfig` is inherited by child models via standard PHP property inheritance. A child model can override it by re-declaring `$auditConfig`, which takes full precedence.

---

License
-------

[](#license)

MIT

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance87

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

134d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/11075330?v=4)[Igor](/maintainers/igrik10)[@igrik10](https://github.com/igrik10)

---

Top Contributors

[![Ihor-Lunhu](https://avatars.githubusercontent.com/u/138585825?v=4)](https://github.com/Ihor-Lunhu "Ihor-Lunhu (3 commits)")[![igrik10](https://avatars.githubusercontent.com/u/11075330?v=4)](https://github.com/igrik10 "igrik10 (1 commits)")

---

Tags

laravelloggingAuditnovachangelog

### Embed Badge

![Health badge](/badges/deltawhydev-laravel-audit-logging/health.svg)

```
[![Health](https://phpackages.com/badges/deltawhydev-laravel-audit-logging/health.svg)](https://phpackages.com/packages/deltawhydev-laravel-audit-logging)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M194](/packages/laravel-ai)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M165](/packages/spatie-laravel-health)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[illuminate/queue

The Illuminate Queue package.

21332.6M1.6k](/packages/illuminate-queue)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k91.9k1](/packages/mike-bronner-laravel-model-caching)[api-platform/laravel

API Platform support for Laravel

58171.6k14](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
