maksudur-dev / laravel-logpilot
A lightweight activity logging package for Laravel with request tracing.
Requires
- php: ^7.3|^8.0
- illuminate/console: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/http: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/log: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^6.0|^7.0|^8.0|^9.0|^10.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.
- 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
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
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:
GET /api/activity-logs: All logs.GET /api/activity-logs/trace/{log_id}: Trace a full request lifecycle.GET /api/activity-logs/model/{type}/{id}: Activity for a specific resource.
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.