bilfeldt/laravel-correlation-id
Laravel middleware that ensures every request has a globally unique Correlation-ID (and echoes any client Request-ID), adds them to the request/response headers, and injects both into the global log context for easier tracing across services, APIs, and jobs.
Install the package:
composer require bilfeldt/laravel-correlation-id
Register middleware (choose one based on Laravel version):
bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->prepend(\Bilfeldt\CorrelationId\Middleware\CorrelationIdMiddleware::class);
$middleware->prepend(\Bilfeldt\CorrelationId\Middleware\ClientRequestIdMiddleware::class);
$middleware->prepend(\Bilfeldt\CorrelationId\Middleware\LogContextMiddleware::class);
})
app/Http/Kernel.php (order matters—place these first):
protected $middleware = [
\Bilfeldt\CorrelationId\Middleware\CorrelationIdMiddleware::class,
\Bilfeldt\CorrelationId\Middleware\ClientRequestIdMiddleware::class,
\Bilfeldt\CorrelationId\Middleware\LogContextMiddleware::class,
// ... other middleware
];
First use case: Access IDs in a controller or service:
$correlationId = request()->getCorrelationId(); // e.g., "a1b2c3d4..."
$clientRequestId = request()->getClientRequestId(); // e.g., "client-provided-id"
Request Entry:
CorrelationIdMiddleware generates a UUID and attaches it to:
Correlation-IDCorrelation-IDClientRequestIdMiddleware echoes the client’s X-Request-ID header in the response.Context Propagation:
LogContextMiddleware injects IDs into Laravel’s global log context (via Log::sharedContext()).{
"level": "info",
"message": "User logged in",
"context": {
"correlation_id": "a1b2c3d4...",
"request_id": "client-provided-id"
}
}
Job Queues:
$job->payload()['data']['correlation_id']; // Access via $job->payload()
request()->getCorrelationId() in job dispatchers to ensure consistency:
MyJob::dispatch()->onQueue('high')->withContext([
'correlation_id' => request()->getCorrelationId(),
]);
Error Handling:
App\Exceptions\Handler to include IDs in error reports:
protected function context(): array {
return array_merge(parent::context(), [
'correlation_id' => request()->getCorrelationId(),
'request_id' => request()->getClientRequestId(),
]);
}
Correlation-ID headers. Example (PHP cURL):
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Correlation-ID: ' . request()->getCorrelationId(),
]);
Request macros in tests:
$request->shouldReceive('getCorrelationId')->andReturn('test-id-123');
getUniqueId() (alias for getCorrelationId()) for backward compatibility.Middleware Order:
CorrelationIdMiddleware first in the stack. If another middleware modifies the request before this runs, the ID may be lost.LogContextMiddleware must run after CorrelationIdMiddleware to capture IDs.Binary Responses:
return response()->file('path/to/file.pdf');
Queue Workers:
Request instance is initialized with the ID. Use the JobContextMiddleware (if available in future versions) or manually inject IDs:
$job->handle(request()->create('/dummy', 'GET', [], [], [], ['correlation_id' => request()->getCorrelationId()]));
Log Context Leakage:
Log::withContext() sparingly:
Log::withContext(['correlation_id' => $id])->info('Safe log message');
Missing IDs?:
CorrelationIdMiddleware vs. CorrelationId).dd(request()->headers->all()) to inspect headers during development.Log Context Not Appearing:
LogContextMiddleware is enabled and runs after ID generation.Job IDs Not Propagating:
payload() includes the data key. If not, manually attach IDs:
MyJob::dispatch()->withContext(['correlation_id' => request()->getCorrelationId()]);
Custom ID Generation:
CorrelationIdGenerator:
$this->app->bind(\Bilfeldt\CorrelationId\Contracts\CorrelationIdGenerator::class, function () {
return new CustomGenerator();
});
Header Names:
$middleware->setHeaderName('X-Custom-ID');
Additional Context:
LogContextMiddleware to include extra data (e.g., user agent):
Log::sharedContext()->set('user_agent', request()->userAgent());
Testing Utilities:
function setTestCorrelationId(string $id) {
app()->make(\Illuminate\Http\Request::class)->setCorrelationId($id);
}
How can I help you explore Laravel packages today?