maksudur-dev / laravel-logpilot
A lightweight activity logging package for Laravel with request tracing.
Requires
- php: ^8.1
- illuminate/console: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
- illuminate/database: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
- illuminate/log: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^6.0|^7.0|^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^9.5|^10.0|^11.0
README
A lightweight Laravel activity logging package that improves debugging, tracing, and business-event visibility while using Laravel's EXISTING logging system or a database.
Key Features
- Request Tracing: Group multiple logs under a single
log_idautomatically. - Dual Drivers: Support for Laravel Logs, Database, or both.
- Auto-Context: Automatically captures User ID, IP, URL, and Method.
- Model Support: Easily associate activities with Eloquent models.
- API Support: Optional API endpoints to view activity logs.
- Artisan Commands: Install, prune, and test your setup easily.
- Laravel 8-13 & PHP 8.1+: Compatible with Laravel 8, 9, 10, 11, 12, and 13.
- Lightweight: Zero-config by default, minimal overhead.
Installation
You can install the package via composer:
composer require maksudur-dev/laravel-logpilot
Run the installation command:
php artisan activity:install
If you are using the database driver, run the migrations:
php artisan migrate
Updating Package
To update the package to the latest version (v1.0.3):
composer update maksudur-dev/laravel-logpilot
Or target the version explicitly:
composer require maksudur-dev/laravel-logpilot:^1.0.3
If you are developing locally with a path repository in composer.json, simply run:
composer update maksudur-dev/laravel-logpilot
Configuration
The configuration file is located at config/logpilot.php.
return [ 'enabled' => env('LOGPILOT_ENABLED', true), 'driver' => env('LOGPILOT_DRIVER', 'log'), // log, database, both 'channel' => env('LOGPILOT_CHANNEL', null), // default log channel 'auto_group_id' => true, 'store_request_context' => true, 'api_enabled' => env('LOGPILOT_API_ENABLED', false), 'queue' => env('LOGPILOT_QUEUE', false), 'retention_days' => 30, ];
Usage
1. Global Helper (Quickest)
activity('user_login'); // With details activity('profile_updated', $user, 'User updated their profile photo'); // With array message (automatically cast to JSON) activity('api_response', null, [ 'status' => 'success', 'data' => ['id' => 1] ]); // Full control activity( action: 'withdraw_request', model: $user, message: 'Gateway timeout', level: 'error', meta: ['amount' => 500] );
2. Eloquent Trait (Recommended for Models)
Add the LogsActivity trait to your models:
use LaravelLogPilot\Traits\LogsActivity; class Order extends Model { use LogsActivity; } // Now you can do: $order->logActivity('shipped', 'Order has been shipped to customer'); // Retrieve logs for this model: $logs = $order->activities;
3. Service Usage
Inject the ActivityLogger service into your classes:
use LaravelLogPilot\Services\ActivityLogger; class PaymentService { public function __construct(protected ActivityLogger $logger) {} public function process() { $this->logger->log('payment_started'); } }
4. Grouping Related Logs (Tracing)
Perfect for complex flows like checkouts or background jobs:
activity_group('checkout_flow_001'); activity('cart_validated'); activity('payment_processing'); activity('order_created'); // All will share log_id: checkout_flow_001
5. Clean Architecture (DTOs, Enums & Services)
LogPilot uses Clean Architecture patterns out-of-the-box. You can leverage Enums, DTOs, and Services in your application:
Enums
use LaravelLogPilot\Enums\LogLevel; use LaravelLogPilot\Enums\ActivityAction; activity( action: ActivityAction::UPDATED->value, message: 'User profile updated', level: LogLevel::WARNING );
ActivityService & DTOs
use LaravelLogPilot\Services\ActivityService; use LaravelLogPilot\DataTransferObjects\ActivityQueryDTO; class ActivityReportController { public function __construct(protected ActivityService $activityService) {} public function index(Request $request) { $dto = ActivityQueryDTO::fromRequest($request); $paginatedLogs = $this->activityService->getPaginatedLogs($dto); return response()->json($paginatedLogs); } }
Encapsulated Model Query Methods
use LaravelLogPilot\Models\ActivityLog; // Filtered logs via DTO $logs = ActivityLog::fetchFiltered($queryDTO); // Grouped trace logs by log_id $traceLogs = ActivityLog::fetchByGroup('checkout_flow_001'); // Logs for a specific Eloquent model $modelLogs = ActivityLog::fetchForModel(User::class, 1, perPage: 15);
Frontend Integration (Vue/React Example)
Since LogPilot provides an API, you can easily build a "Recent Activity" component.
Example Vue Component
<template> <div class="activity-feed"> <div v-for="log in logs" :key="log.id" class="log-item"> <span class="badge" :class="log.level">{{ log.action }}</span> <p v-if="typeof log.message === 'string'">{{ log.message }}</p> <pre v-else>{{ JSON.stringify(log.message, null, 2) }}</pre> <small>{{ formatDate(log.created_at) }}</small> </div> </div> </template> <script setup> import { ref, onMounted } from 'vue'; const props = defineProps(['modelType', 'modelId']); const logs = ref([]); onMounted(async () => { const response = await fetch(`/api/activity-logs/model/${props.modelType}/${props.modelId}`); const data = await response.json(); logs.value = data.data; }); </script>
Example React Component
import React, { useState, useEffect } from 'react'; const ActivityFeed = ({ modelType, modelId }) => { const [logs, setLogs] = useState([]); useEffect(() => { fetch(`/api/activity-logs/model/${modelType}/${modelId}`) .then(res => res.json()) .then(data => setLogs(data.data)); }, [modelType, modelId]); return ( <div className="activity-feed"> {logs.map(log => ( <div key={log.id} className={`log-item ${log.level}`}> <span className="badge">{log.action}</span> {typeof log.message === 'object' ? ( <pre>{JSON.stringify(log.message, null, 2)}</pre> ) : ( <p>{log.message}</p> )} <small>{new Date(log.created_at).toLocaleString()}</small> </div> ))} </div> ); }; export default ActivityFeed;
Example Blade Component
If you prefer server-side rendering, you can pass logs to a Blade component:
{{-- In your controller --}} $logs = $order->activities()->paginate(10); return view('orders.show', compact('order', 'logs')); {{-- In orders/show.blade.php --}} <div class="activity-feed"> @foreach($logs as $log) <div class="log-item {{ $log->level }}"> <strong>{{ $log->action }}</strong> <div> @if(is_array($log->message)) <pre>{{ json_encode($log->message, JSON_PRETTY_PRINT) }}</pre> @else {{ $log->message }} @endif </div> <small>{{ $log->created_at->diffForHumans() }}</small> </div> @endforeach {{ $logs->links() }} </div>
API Support
LogPilot exposes clean, JSON-ready endpoints with comprehensive search, filtering, and pagination support:
GET /api/activity-logs: List and filter activity logs.GET /api/activity-logs/levels: Get all log levels formatted for frontend select/dropdown inputs.GET /api/activity-logs/trace/{log_id}: Trace a full request lifecycle bylog_id.GET /api/activity-logs/model/{type}/{id}: Activity for a specific resource.
Query Parameters & Filtering (GET /api/activity-logs)
You can pass query parameters to filter, search, and paginate logs:
| Parameter | Type | Description | Example |
|---|---|---|---|
search / q / query |
string |
Search across action, message, url, log_id, ip, and model_type fields. |
?search=Failed |
level |
string |
Filter by log level (case-insensitive: error, warning, info, debug, critical, alert, emergency, notice). Pass all or empty to include all levels. |
?level=Error |
action |
string |
Filter by exact action name. | ?action=USER_LOGIN |
user_id |
mixed |
Filter logs for a specific User ID. | ?user_id=42 |
log_id |
string |
Filter logs by trace ID (log_id). |
?log_id=c2753c6f-6f06-... |
model_type |
string |
Filter logs for a specific model class. | ?model_type=App\Models\User |
model_id |
mixed |
Filter logs for a specific model ID. | ?model_id=5 |
start_date / date_from / from |
date |
Filter logs created on or after date/time. | ?start_date=2026-08-01 |
end_date / date_to / to |
date |
Filter logs created on or before date/time. | ?end_date=2026-08-14 |
per_page |
integer |
Results per page (default: 20, max: 500). |
?per_page=50 |
page |
integer |
Page number for pagination (default: 1). |
?page=2 |
Filtering Example
GET /api/activity-logs?search=Reward&level=Error&per_page=20&page=1
Artisan Commands
php artisan activity:install: Setup everything.php artisan activity:prune: Cleanup old logs.php artisan activity:test: Verify installation.
License
The MIT License (MIT). Please see License File for more information.