The 3am incident use case
A customer reports their checkout failed at 14:23. Without a correlation ID, you grep logs by timestamp + user ID, miss half the story because cross-service logs don't share keys, and reconstruct the flow by guessing. With a correlation ID: one grep 'req_5c1d...' across every log source and you have the full timeline.
Implementing in Laravel
app/Http/Middleware/AssignRequestId.php
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class AssignRequestId
{
public function handle(Request $request, Closure $next)
{
$id = $request->header('X-Request-Id', Str::uuid()->toString());
Log::withContext([
'request_id' => $id,
'user_id' => auth()->id(),
'route' => $request->route()?->uri(),
]);
$response = $next($request);
$response->headers->set('X-Request-Id', $id);
return $response;
}
}
Register globally in bootstrap/app.php. Every subsequent log line in that request carries request_id. The response header lets clients report the ID when filing bug reports.
Propagating to outbound HTTP
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'X-Request-Id' => request()->header('X-Request-Id'),
'traceparent' => request()->header('traceparent'), // if using OTel
])->get($url);
Or set it once via a Laravel Http::macro() so it's automatic on every outbound call.
Correlation ID vs trace ID
Pre-OpenTelemetry era: X-Request-Id was the common header, implementations varied. Post-OTel: use W3C traceparent — it encodes trace_id + span_id + sampling flag in one header, and every OTel-instrumented service understands it natively.
For interoperability, send both. X-Request-Id for simple log correlation, traceparent for tracing tooling. They can share the same underlying UUID if you want.
What to include in log context
Beyond the correlation ID itself:
user_id(hashed or numeric, not PII)routeorcontrollerdeploy_sha(git SHA of the running build)env(production, staging)