noartem / laravel-wide-events
Wide Events for Laravel.
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- laravel/framework: ^10.0|^11.0|^12.0
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^10.5|^11.0
README
This package implements wide events: build one structured event per request, enrich it throughout the request lifecycle, then emit once at the end with tail sampling.
More about wide events and why traditional logging suck you can find out at loggingsucks.com.
Quick start
- Install package
composer require noartem/laravel-wide-events php artisan vendor:publish --tag=wide-events-config
- Register middleware (early in the stack)
// bootstrap/app.php use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withMiddleware(function (Middleware $middleware) { $middleware->append(\Noartem\LaravelWideEvents\Http\Middleware\InitWideEvent::class); // ... other middlewares }) ->create();
If you are still using app/Http/Kernel.php, add the middleware to $middleware there instead.
- Enrich anywhere in code
use Illuminate\Support\Facades\Log; Log::wideEvent('user.id', auth()->id()); Log::wideEvent('cart.total_cents', 12345);
- Customize sampling
// config/wide-events.php 'sampler' => App\Logging\CustomWideEventSampler::class,
Your class must implement WideEventSampler. Or extend default implementation: DefaultWideEventSampler. More examples of samplers in examples/.
Custom collectors
Register extra collectors in config:
// config/wide-events.php 'collectors' => [ App\Logging\CheckoutCollector::class, ],
A collector should extend the base class and map events to handlers:
use Noartem\LaravelWideEvents\Collectors\BaseCollector; use Illuminate\Routing\Events\RouteMatched; final class CheckoutCollector extends BaseCollector { public function events(): array { return [RouteMatched::class => 'onRoute']; } public function onRoute(RouteMatched $event): void { $this->put('route.name', $event->route->getName()); } }
Default sampling behavior
By default the sampler keeps:
- all requests with exceptions or 5xx
- requests slower than the configured percentile of recent durations
- a deterministic sample of the rest
Sanitization
Redaction is applied by key and value patterns. Update wide-events.redaction in the config to add your own key names or regexes for sensitive values (Stripe, GitHub, JWT, etc).
Output format
A single log record:
- message:
wide_event(configurable) - context: the wide event payload (array)
Use a JSON formatter on the chosen channel for best results.