aubes/correlation-bundle

Correlation ID propagation for Symfony: storage, generation, HTTP, and optional integrations for Monolog, Messenger, Mercure, and HTTP Client

Maintainers

Package info

github.com/aubes/correlation-bundle

Type:symfony-bundle

pkg:composer/aubes/correlation-bundle

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-04-11 10:56 UTC

This package is auto-updated.

Last update: 2026-04-11 11:25:38 UTC


README

CI Latest Stable Version PHP Version License

Lightweight distributed tracing for Symfony. Propagates a correlation ID across your entire stack (HTTP, HTTP Client, Monolog, Messenger, Mercure, Twig) without the overhead of a full APM solution.

Worker-mode ready: the storage implements ResetInterface and is scoped per request/message. Works out of the box with FrankenPHP worker mode and Messenger workers.

Requirements

  • PHP >= 8.2
  • Symfony 6.4 / 7.4 / 8.x

Installation

composer require aubes/correlation-bundle

The bundle auto-registers via Symfony Flex.

How it works

The bundle captures or generates a correlation ID at the start of each HTTP request or console command, stores it in a request-scoped storage, and propagates it to all configured integrations.

Core (always active)

  • Storage: CorrelationIdStorage is final, self-materializes a UUID v7 via the configured generator on first get(), and memoizes the result
  • Contract: CorrelationIdProviderInterface::get() always returns a valid, non-null string
  • Validation: set() validates its input (printable ASCII, 1-255 chars) and throws InvalidCorrelationIdException on invalid values. Last write wins
  • Reset: implements ResetInterface for worker/long-running process safety
  • Console: correlation ID generated automatically per command, overridable via --correlation-id

HTTP (always active)

  • Captures X-Correlation-Id from incoming requests (configurable header name)
  • Generates a new ID when the header is missing
  • Echoes the ID in the response header

Optional integrations

Each integration activates automatically when its dependency is installed, and can be explicitly disabled.

Integration Dependency What it does
HTTP Client symfony/http-client Forwards the correlation ID as a header on outgoing HTTP requests. Any caller-provided correlation header is overwritten (the storage is the single source of truth)
Monolog monolog/monolog Injects the ID into every log record's extra array
Messenger symfony/messenger Stamps the ID on dispatch, restores it on consume
Mercure symfony/mercure-bundle Injects the ID into JSON object payloads
Twig twig/twig Provides a correlation_id() template function

Configuration

# config/packages/correlation.yaml
correlation:
    # Core
    generator: 'Aubes\CorrelationBundle\Generator\UuidCorrelationIdGenerator'
    uuid_version: 7  # 4, 6, or 7

    # HTTP
    http:
        header_name: 'X-Correlation-Id'
        send_response_header: true

    # Optional integrations
    http_client:
        enabled: true
        header: 'X-Correlation-Id'
        force_header: true  # false = caller-provided header takes precedence
        clients: ['http_client']

    monolog:
        enabled: true
        field_name: 'correlation_id'
        channels: []   # empty = all channels
        handlers: []   # empty = all handlers

    messenger:
        enabled: true
        buses: []      # empty = all buses

    mercure:
        enabled: true
        field_name: 'correlation_id'
        hubs: ['default']

    twig:
        enabled: true

All values shown above are defaults. Zero configuration is needed for the common case.

Interfaces

CorrelationIdProviderInterface

Read-only access. Inject this when you only need to read the current ID.

use Aubes\CorrelationBundle\Storage\CorrelationIdProviderInterface;

final class MyService
{
    public function __construct(private readonly CorrelationIdProviderInterface $provider) {}

    public function doSomething(): void
    {
        $correlationId = $this->provider->get(); // guaranteed non-null
    }
}

CorrelationIdStorageInterface

Full access: read, write, and reset. Extends CorrelationIdProviderInterface and ResetInterface.

public function get(): string;
public function set(string $id): void; // throws InvalidCorrelationIdException
public function reset(): void;

CorrelationIdGeneratorInterface

public function generate(): string;

Extension points

Swap the generator

use Aubes\CorrelationBundle\Generator\CorrelationIdGeneratorInterface;

final class MyGenerator implements CorrelationIdGeneratorInterface
{
    public function generate(): string
    {
        return bin2hex(random_bytes(16));
    }
}
correlation:
    generator: App\MyGenerator

Note: the service referenced by generator must implement Aubes\CorrelationBundle\Generator\CorrelationIdGeneratorInterface.

Seed the ID from a custom context

Inject CorrelationIdStorageInterface and call $storage->set($id) before the first downstream read:

use Aubes\CorrelationBundle\Exception\InvalidCorrelationIdException;

try {
    $storage->set($idFromExternalSource);
} catch (InvalidCorrelationIdException) {
    // untrusted source: fall back to the generator
}

Debug

The correlation:debug command displays active integrations, the generator class, and the current correlation ID:

php bin/console correlation:debug

When the Web Profiler is enabled, a correlation ID panel shows the ID source (generated vs provided) and the list of active integrations.

License

MIT