Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# LogiAudit

LogiAudit is a Laravel package designed for structured logging with support for job-based log storage, pruning, and
customizable log levels.
LogiAudit is a Laravel package designed for structured logging and audit trail with support for job-based log storage,
pruning, and customizable log levels.

## Features

- **Queue-Based Logging**: Logs are stored asynchronously using Laravel jobs.
- **Contextual Logging**: Supports logging with model associations, trace IDs, and additional metadata.
- **Contextual Logging**: Supports logging with model associations, trace IDs, tags, and additional metadata.
- **Automatic Pruning**: Logs marked as deletable can be automatically removed.
- **Monolog Integration**: Works seamlessly with Laravel's logging system.
- **IP Tracking**: Logs IP addresses for traceability.
- **Configurable Cleanup**: Define log retention periods.
- **Tag Filtering**: Tag your logs for easy filtering and categorization.
- **Audit Trail**: Automatically track model changes (create, update, delete) with old/new values.

## Installation

Expand All @@ -22,7 +24,7 @@ composer require aurorawebsoftware/logiaudit

### Running Migrations

After installation, run the migration command to create the necessary database table:
After installation, run the migration command to create the necessary database tables:

```bash
php artisan migrate
Expand All @@ -39,6 +41,7 @@ addLog('info', 'User logged in', [
'model_id' => $user->id,
'model_type' => get_class($user),
'trace_id' => Str::uuid(),
'tag' => 'auth',
'context' => ['role' => 'admin'],
'ip_address' => request()->ip(),
'deletable' => true,
Expand All @@ -56,6 +59,7 @@ The `addLog` function allows for flexible logging with optional parameters:
- `model_id` (int, nullable): The ID of the related model (if applicable).
- `model_type` (string, nullable): The model's class name.
- `trace_id` (string, nullable): A unique identifier for tracing logs across multiple services.
- `tag` (string, nullable): A tag for filtering and categorizing logs (e.g., `payment`, `auth`, `api`).
- `context` (array, nullable): Any extra contextual data.
- `ip_address` (string, nullable): The IP address of the request.
- `deletable` (bool, default: `true`): Determines if the log can be pruned.
Expand All @@ -73,6 +77,7 @@ Log::channel('logiaudit')->info('Custom log message', [
'model_id' => 1,
'model_type' => 'User',
'trace_id' => Str::uuid(),
'tag' => 'payment',
'context' => ['key' => 'value'],
'ip_address' => request()->ip(),
]);
Expand All @@ -97,22 +102,26 @@ To remove logs marked as `deletable`, run the following command:
php artisan logs:prune
```

Alternatively, you can schedule this command in your `app/Console/Kernel.php`:
Alternatively, you can schedule this command in your `bootstrap/app.php` (Laravel 11+):

```php
protected function schedule(Schedule $schedule)
{
->withSchedule(function (Schedule $schedule) {
$schedule->command('logs:prune')->daily();
}
})
```

# History Usage

History Log is simple to use. When you call **HistoryableTrait** into your model classes whose history you want to
History Log is simple to use. When you add **LogiAuditTrait** to your model classes whose history you want to
monitor, History Log will start to keep history for your model.

```php
use LogiAuditTrait;
use AuroraWebSoftware\LogiAudit\Traits\LogiAuditTrait;

class Order extends Model
{
use LogiAuditTrait;
}
```

If you want to exclude some columns from this, add this variable to your model class globally and write the column names
Expand All @@ -122,16 +131,19 @@ as an array.
protected $excludedColumns = ['deleted_at', 'id'];
```

If you don't want to keep history in some model events, add the following variable. Currently, this version only keeps
the history of create, update and delete events.
If you don't want to keep history in some model events, add the following variable. Both short (`create`) and full
(`created`) forms are accepted. Currently, this version only keeps the history of create, update and delete events.

```php
protected $excludedEvents = ['delete', 'create'];
```

| Id | action | table | model | model_id | column | old_value | new_value | user_id | ip_address |
|----|---------|--------|------------------|----------|--------------------------------------------|------------------------------------------------------------|-------------------------------------------------------------|---------|------------|
| 1 | created | orders | App\Models\Order | 5 | [["order_code"],["price"],["total_price"]] | [{"order_code":"ABC"},{"price":"20"},{"total_price":"20"}] | [{"order_code":"ABCD"},{"price":"30"},{"total_price":"60"}] | 2 | 177.77.0.1 |
### Example History Record

| Id | action | table | model | model_id | column | old_value | new_value | user_id | ip_address |
|----|---------|--------|------------------|----------|--------------------------------------------|-----------|------------------------------------------------------------|---------|------------|
| 1 | created | orders | App\Models\Order | 5 | ["order_code","price","total_price"] | null | [{"order_code":"ABCD"},{"price":"30"},{"total_price":"60"}] | 2 | 177.77.0.1 |
| 2 | updated | orders | App\Models\Order | 5 | ["price"] | [{"price":"30"}] | [{"price":"50"}] | 2 | 177.77.0.1 |

## Running the History Pruning Command

Expand Down Expand Up @@ -164,8 +176,8 @@ return [
];
```
If there is no config you can publish
```php
php artisan vendor:publish --tag=logiaudit-config
```bash
php artisan vendor:publish --tag=config
```

## Environment File Setup
Expand All @@ -191,5 +203,3 @@ You can keep the workers running in the background using **supervisor** or **sys
## License

The LogiAudit package is open-sourced software licensed under the MIT License.


5 changes: 1 addition & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@
"laravel": {
"providers": [
"AuroraWebSoftware\\LogiAudit\\LogiAuditServiceProvider"
],
"aliases": {
"LogiAudit": "AuroraWebSoftware\\LogiAudit\\Facades\\LogiAudit"
}
]
}
},
"minimum-stability": "dev",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! Schema::hasColumn('logiaudit_logs', 'logged_at')) {
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->timestamp('logged_at')->nullable()->after('deletable');
});
}
}

/**
* Reverse the migrations.
*/
public function down(): void
{
if (Schema::hasColumn('logiaudit_logs', 'logged_at')) {
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->dropColumn('logged_at');
});
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
$table->string('ip_address')->nullable()->change();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
$table->string('ip_address')->nullable(false)->change();
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('logiaudit_logs', function (Blueprint $table) {
if (Schema::hasColumn('logiaudit_logs', 'deleted_at') && ! Schema::hasColumn('logiaudit_logs', 'expires_at')) {
$table->renameColumn('deleted_at', 'expires_at');
}
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('logiaudit_logs', function (Blueprint $table) {
if (Schema::hasColumn('logiaudit_logs', 'expires_at') && ! Schema::hasColumn('logiaudit_logs', 'deleted_at')) {
$table->renameColumn('expires_at', 'deleted_at');
}
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
$table->unsignedBigInteger('model_id')->nullable(false)->change();
$table->unsignedBigInteger('user_id')->nullable()->change();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
$table->integer('model_id')->nullable(false)->change();
$table->integer('user_id')->nullable()->change();
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->index(['deletable', 'expires_at'], 'logiaudit_logs_prune_index');
});

Schema::table('logiaudit_history', function (Blueprint $table) {
$table->index('created_at', 'logiaudit_history_created_at_index');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->dropIndex('logiaudit_logs_prune_index');
});

Schema::table('logiaudit_history', function (Blueprint $table) {
$table->dropIndex('logiaudit_history_created_at_index');
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! Schema::hasColumn('logiaudit_logs', 'tag')) {
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->string('tag')->nullable()->index()->after('level');
});
}
}

/**
* Reverse the migrations.
*/
public function down(): void
{
if (Schema::hasColumn('logiaudit_logs', 'tag')) {
Schema::table('logiaudit_logs', function (Blueprint $table) {
$table->dropColumn('tag');
});
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
if (! Schema::hasColumn('logiaudit_history', 'causer_type')) {
$table->string('causer_type')->nullable()->after('user_id')->index();
}
});
}

public function down(): void
{
Schema::table('logiaudit_history', function (Blueprint $table) {
if (Schema::hasColumn('logiaudit_history', 'causer_type')) {
$table->dropColumn('causer_type');
}
});
}
};
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ networks:
driver: bridge
ipam:
config:
- subnet: 172.40.10.0/24
- subnet: 172.49.10.0/24
5 changes: 5 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ parameters:
ignoreErrors:
- '#Trait .*?LogiAuditTrait.*? is used zero times and is not analysed#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Model::getExcludedEvents\(\).#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Model::getExcludedColumns\(\).#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Model::getDontLogIfAttributesChangedOnly\(\).#'
-
identifier: larastan.noEnvCallsOutsideOfConfig
path: config/*
6 changes: 3 additions & 3 deletions src/Commands/PruneLogsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class PruneLogsCommand extends Command
{
protected $signature = 'logs:prune';

protected $description = 'Delete all logs with deletable=true and deleted_at in the past.';
protected $description = 'Delete all logs with deletable=true and expires_at in the past.';

public function handle()
{
Expand All @@ -22,8 +22,8 @@ public function handle()

$query = DB::table('logiaudit_logs')
->where('deletable', true)
->whereNotNull('deleted_at')
->where('deleted_at', '<=', $now);
->whereNotNull('expires_at')
->where('expires_at', '<=', $now);

do {
$deleted = $query->take($batchSize)->delete();
Expand Down
Loading
Loading