# Audit Changes Logs

![](https://laraveldaily.com/wp-content/uploads/2019/03/modules-audit-logs-table.png)

&#x20;This module logs all the actions by the users. Every time someone adds/updates/deletes an entry, it will log the action in database table **audit\_logs**, which will be shown in a separate menu item (see above).

![](https://laraveldaily.com/wp-content/uploads/2019/03/modules-audit-logs-database.png)

&#x20;For that, we use [Model Observer](https://laravel.com/docs/5.8/eloquent#observers) functionality of Laravel.

&#x20;Video demo of a module:

{% embed url="<https://www.youtube.com/watch?v=zUIA99xKyJQ>" %}

## How does the result look in QuickAdminPanel code?

&#x20;We create a new database table with migration:

```
Schema::create('audit_logs', function (Blueprint $table) {
    $table->increments('id');
    $table->text('description');
    $table->unsignedInteger('subject_id')->nullable();
    $table->string('subject_type')->nullable();
    $table->unsignedInteger('user_id')->nullable();
    $table->text('properties')->nullable();
    $table->string('host', 45)->nullable();
    $table->timestamps();
});
```

&#x20;Then we create a new model called **app/AuditLog.php**:

```
class AuditLog extends Model
{
    protected $fillable = [
        'description',
        'subject_id',
        'subject_type',
        'user_id',
        'properties',
        'host',
    ];

    protected $casts = [
        'properties' => 'collection',
    ];
}
```

&#x20;Then we create one new **Trait** class, with this code.\
&#x20;**app/Traits/Auditable.php**

```
namespace App\Traits;

use App\AuditLog;
use Illuminate\Database\Eloquent\Model;

trait Auditable
{
    public static function bootAuditable()
    {
        static::created(function (Model $model) {
            self::audit('created', $model);
        });

        static::updated(function (Model $model) {
            self::audit('updated', $model);
        });

        static::deleted(function (Model $model) {
            self::audit('deleted', $model);
        });
    }

    protected static function audit($description, $model)
    {
        AuditLog::create([
            'description'  => $description,
            'subject_id'   => $model->id ?? null,
            'subject_type' => get_class($model) ?? null,
            'user_id'      => auth()->id() ?? null,
            'properties'   => $model ?? null,
            'host'         => request()->ip() ?? null,
        ]);
    }
}
```

&#x20;Then we attach this trait for CRUD model: **app/Project.php:**

```
use App\Traits\Auditable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Project extends Model
{
    use SoftDeletes, Auditable;

    // ...
```

&#x20;Finally, we create a CRUD called **Audit Logs** to just view the table.\
&#x20;**resources/views/admin/auditLogs/index.blade.php**

```
<table class=" table table-bordered table-striped datatable">
<thead>
<tr>
<th>
    {{ trans('global.auditLog.fields.id') }}
</th>
<th>
    {{ trans('global.auditLog.fields.description') }}
</th>
<th>
    {{ trans('global.auditLog.fields.subject_id') }}
</th>
<th>
    {{ trans('global.auditLog.fields.subject_type') }}
</th>
<th>
    {{ trans('global.auditLog.fields.user_id') }}
</th>
<th>
    {{ trans('global.auditLog.fields.host') }}
</th>
<th>
    {{ trans('global.auditLog.fields.created_at') }}
</th>
<th>
 
</th>
</tr>
</thead>
<tbody>
@foreach($auditLogs as $key => $auditLog)
<tr>
    <td>
        {{ $auditLog->id ?? '' }}
    </td>
    <td>
        {{ $auditLog->description ?? '' }}
    </td>
    <td>
        {{ $auditLog->subject_id ?? '' }}
    </td>
    <td>
        {{ $auditLog->subject_type ?? '' }}
    </td>
    <td>
        {{ $auditLog->user_id ?? '' }}
    </td>
    <td>
        {{ $auditLog->host ?? '' }}
    </td>
    <td>
        {{ $auditLog->created_at ?? '' }}
    </td>
    <td>
        @can('audit_log_show')
            <a class="btn btn-xs btn-primary" href="{{ route('admin.audit-logs.show', $auditLog->id) }}">
                {{ trans('global.view') }}
            </a>
        @endcan
        @can('audit_log_edit')
            <a class="btn btn-xs btn-info" href="{{ route('admin.audit-logs.edit', $auditLog->id) }}">
                {{ trans('global.edit') }}
            </a>
        @endcan
        @can('audit_log_delete')
            <form action="{{ route('admin.audit-logs.destroy', $auditLog->id) }}" method="POST" onsubmit="return confirm('{{ trans('global.areYouSure') }}');" style="display: inline-block;">
                <input type="hidden" name="_method" value="DELETE">
                <input type="hidden" name="_token" value="{{ csrf_token() }}">
                <input type="submit" class="btn btn-xs btn-danger" value="{{ trans('global.delete') }}">
            </form>
        @endcan
    </td>

</tr>
@endforeach
</tbody>
</table>
```

&#x20;You can easily customize the module after download by adding more fields or more logic in the files above.

## How to install/use the module?

&#x20;All you need to do is go to your panel's **Modules** menu item, find the module in the list and click **Install**.

![](https://laraveldaily.com/wp-content/uploads/2019/03/modules-audit-logs-install.png)

&#x20;Then for every CRUD you may specify to enable Audit Logs for that CRUD.

![](https://laraveldaily.com/wp-content/uploads/2019/03/modules-audit-logs-crud.png)

## How to Customize the Module

{% embed url="<https://www.youtube.com/watch?v=8L2Jzo0tVpE>" %}

## More information

* [Eloquent Observers](https://laravel.com/docs/master/eloquent#observers)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://helpdocs.quickadminpanel.com/modules/audit-changes-logs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
