Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Correlation Ids Bundle Laravel Package

softwax/correlation-ids-bundle

A PHP/Symfony bundle that generates and propagates correlation IDs across requests, responses, and logs, making it easier to trace distributed transactions and debug issues end-to-end.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Read src/ before installing. This is published as a Symfony bundle (*Bundle suffix, SoftWax vendor), not a Laravel package. The two things you actually care about live there: the DI extension/config class, and the request/response event subscriber that generates the ID, reads the inbound header, and writes it back. Those ~50 lines are the whole product; everything else is framework glue you will likely replace.
  • Resolve the framework question first. Check composer.json for symfony/framework-bundle / symfony/http-kernel requirements. If it is Symfony-only, do not fight it into Laravel's container — port the behaviour into a middleware and a Monolog processor. For a concern this small, reimplementation is usually cheaper and removes a pre-1.0 dependency from every service's logging path.
  • Pin the version. "softwax/correlation-ids-bundle": "0.1.*" or an exact tag. Release 0.1 has no changelog body, only a commit-range link, so there is no documented BC promise. Treat any bump as potentially breaking.
  • Ship one thin vertical slice first, in this order:
    1. Generate (or accept) an ID at the start of the request.
    2. Return it on the response header (X-Correlation-ID / X-Request-ID).
    3. Push it into the log context so every line for the request carries it.
  • Verify against a real request immediately. curl -i your health route and a route that logs, and confirm (a) the response header is present and stable, (b) the log line contains the same value as structured context. If either half fails, nothing downstream matters.
  • Decide the trust policy on day one. Whether you honour an inbound ID or always regenerate is the single decision that drives both your debugging value and your security exposure. Only trust IDs from your own gateway/load balancer.

Minimal Laravel shape to aim for (the "port, don't bundle" path):

// app/Http/Middleware/CorrelationId.php
public function handle($request, Closure $next)
{
    $incoming = $request->header('X-Correlation-ID');
    $id = $incoming && $this->isTrusted($request) && $this->validFormat($incoming)
        ? $incoming
        : (string) Str::uuid();

    CorrelationContext::set($id);
    Log::withContext(['correlation_id' => $id]);

    try {
        $response = $next($request);
    } finally {
        // runs for 4xx/5xx too
        $response ??= response();
        $response->headers->set('X-Correlation-ID', $id);
    }

    return $response;
}

Implementation Patterns

  • Middleware-centric flow. Register globally (not per-route) so it runs before anything that might log. Resolve the ID, stash it on a small holder/Context, and set the response header in finally so error responses carry it.
  • Stable log key everywhere. Pick correlation_id and use the same key in web, queue, console, and scheduler. Log queries that join across services depend on the key name being boring and constant. Keep it in the record's context (structured field), not interpolated into the message string.
  • Outbound HTTP propagation. Add a Http::globalMiddleware (or Guzzle middleware) that copies the ID onto outgoing requests. This is what makes the ID actually worth having — without it you only have per-app IDs that don't join at service boundaries.
  • Queue jobs. Capture the ID at dispatch time (job property or payload), and restore it in the worker before handle() runs. Reset after the job. The worker is long-lived; a static holder that is not reset will attribute the next job's logs to the previous job.
  • Console/commands. Decide explicitly: fresh ID per invocation is fine for interactive commands; for scheduled jobs derive a deterministic ID from schedule name + timestamp so repeated runs are distinguishable in logs.
  • Configuration surface. Expect/design options for header name, trust-inbound flag (or trusted-proxy list), ID format/prefix, and excluded paths (health checks, metrics endpoints). Mirror these into config/correlation.php rather than hard-coding — you will want to exclude /up and /metrics.
  • Octane and RoadRunner. Bind the holder as a scoped instance ($app->scoped(...)) rather than a singleton, and flush it in a terminating callback. Scoped bindings are the mechanism that makes per-request state safe in long-lived workers.
  • Integration with existing observability. If you already run OpenTelemetry, Sentry, or a service mesh, decide which identifier is canonical before rollout. Most teams use the trace ID as the canonical ID and the correlation ID only for the edge/gateway boundary — two competing IDs produce ambiguous runbooks.
  • Testing. Feature test with a fixed inbound header and assert both the response header and the log context match. Use Log::spy() or a test log handler to assert the field. Set the trust flag true for the test so the fixed header is honoured.

Gotchas and Tips

  • Framework mismatch is the main risk. A Symfony bundle will not auto-register in Laravel. Either write a service provider + bindings, or (usually better) reimplement the ~50 lines. Weigh the Symfony dependency cost: pulling symfony/http-kernel into a Laravel app for a header is a poor trade.
  • Header spoofing. An inbound X-Correlation-ID is attacker-controlled input that flows into logs and onward downstream. Validate format and length (e.g. strict UUID/ULID regex), or simply overwrite inbound values from untrusted sources. Unvalidated IDs enable log injection and unbounded log-field cardinality.
  • Async context loss is silent and common. The ID does not survive queue jobs, events/listeners, Http::pool(), or deferred callbacks automatically. Every exit from the request lifecycle needs explicit propagation. Instrument for the missing ID case — a worker logging without a correlation ID is the failure mode you'll hit first.
  • Long-lived worker bleed-through. Octane and queue workers reuse process state. If the holder is a singleton and you forget to reset, a previous request's ID shows up on the current one — worse than no ID, because it silently corrupts investigations. Test this explicitly with two sequential requests/jobs.
  • Error paths. If you set the response header only on the happy path, your 4xx/5xx responses — the ones you actually debug — will be missing it. Set it in finally or via a response event.
  • Cardinality trap. Correlation IDs belong in message context, never as a metric label or a database index key. High-cardinality labels will inflate your observability bill and index storage in proportion to request volume.
  • Config caching. After changing header names or middleware config, run php artisan config:clear. Stale cached config is the usual reason a header name "silently doesn't change".
  • Upgrade breakage is quiet. A pre-1.0 minor bump that renames the header or config key stops propagation downstream while logging keeps working — you notice during an incident, not at deploy. Pin 0.1.*, read the commit range on every bump, and keep the integration surface thin so replacement stays cheap.
  • Keep the ID opaque. The ID itself carries no PII, but resist packing user or tenant identifiers into it. Look those up separately; opaque IDs are safer to log and forward.
  • Log pipeline limits. A malformed or oversized ID can cause a structured-log record to be rejected or truncated at the aggregator. Cap ID length at generation/validation time.
  • No PII, no business meaning, no secrets — treat the ID as a correlation token only, and document that in your runbook alongside the header name and trust policy.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route