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 Monolog Laravel Package

manomano-tech/correlation-ids-monolog

Monolog processor that injects correlation IDs into every log record, with built-in support for ManoMano's correlation ID conventions and propagation, making it easy to trace requests across services in Laravel and PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a thin glue package: it contains (almost certainly) a single Monolog processor class that reads the current correlation ID from manomano-tech/correlation-ids and copies it onto every LogRecord. Treat it as ~50 lines of source you can read in a minute, not a framework.

1. Install

composer require manomano-tech/correlation-ids-monolog

This pulls in manomano-tech/correlation-ids transitively. Note the last release is from September 2018 — expect PHP 7.x / Monolog 1.x era code. Verify compatibility against your Monolog (2/3) and PHP (8.x) before adopting; if either fails, vendor a fork instead of waiting for upstream.

2. Find the processor class first

Browse vendor/manomano-tech/correlation-ids-monolog/src/. The processor is the only meaningful class. Confirm the exact FQCN and — critically — which key it writes to (extra.correlation_id, context.correlation_id, etc.). Everything downstream (formatter, index mapping, log queries) depends on that key, so get it from the source rather than guessing:

composer show manomano-tech/correlation-ids-monolog
grep -r "record\[" vendor/manomano-tech/correlation-ids-monolog/src

3. Set the correlation ID as early as possible

The parent package holds the ID; the processor just reads it. Seed it at the request boundary:

use CorrelationIds\CorrelationIds; // confirm namespace in vendor/

$correlationId = $_SERVER['HTTP_X_CORRELATION_ID']
    ?? CorrelationIds::generate();          // confirm generator method name

CorrelationIds::getInstance()->setCorrelationId($correlationId);

4. Register the processor with Monolog

$logger = new \Monolog\Logger('app');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout'));
$logger->pushProcessor(new CorrelationIds\Monolog\Processor\CorrelationIdProcessor());

First use case worth validating: a single inbound HTTP request produces log lines across web + queue worker + downstream service, all tagged with the same ID, so you can grep one ID and see the whole trace. If you can't demonstrate that end-to-end in an afternoon, the integration isn't done.


Implementation Patterns

Processor placement: global, not per-channel. In practice you want the ID on every channel. Push it on the logger factory / root logger so all children inherit it, rather than re-registering per channel.

Symfony: tag as a Monolog processor. This is the idiomatic integration and avoids manual wiring:

# config/services.yaml
services:
    CorrelationIds\Monolog\Processor\CorrelationIdProcessor:
        tags:
            - { name: monolog.processor }

Symfony: middleware/event listener for the ID. Set the correlation ID in a kernel request listener (kernel.request, high priority) so it's populated before anything else logs. If the parent package ships an HTTP middleware, prefer it — it also handles inbound header parsing and outbound propagation for you.

Format the ID into the message line. With a line formatter:

monolog:
    handlers:
        main:
            formatter: monolog.formatter.line
            # "%datetime% %channel% %level_name% [%extra.correlation_id%] %message%\n"

For JsonFormatter, extra fields are serialized automatically — no formatter config needed, and this is the better choice if you ship logs to ELK/Loki/Datadog where you want the ID as a queryable field rather than a substring.

Propagate into async work. Correlation IDs die at the queue boundary unless you carry them. Serialize the ID into the job payload on dispatch and restore it at the top of the worker:

// dispatch
$payload['_correlation_id'] = CorrelationIds::getInstance()->getCorrelationId();

// worker bootstrap
CorrelationIds::getInstance()->setCorrelationId($payload['_correlation_id'] ?? CorrelationIds::generate());

The same applies to HTTP clients calling downstream services — the parent package likely has an outbound-header helper; if not, add the header manually in your Guzzle middleware.

CLI and cron. No inbound header exists. Generate an ID at the top of every command so long-running jobs are traceable, and log it once at startup.

If the parent package is plural ("correlation-ids"), check whether it models a chain (e.g., request id + parent id + batch id). If so, map the whole set into extra rather than flattening to one string — you'll regret losing the parent link when debugging a fan-out.

If you already run OpenTelemetry / a tracing SDK, skip this package. A three-line custom processor that reads your existing trace ID gives you the same result with one fewer dependency and no singleton.


Gotchas and Tips

  • Archived and unmaintained. 2 stars, 0 dependents, last release 2018. No upstream fixes will arrive. Budget for reading/patching the source yourself, or write the equivalent processor — it's genuinely trivial — and avoid the dependency entirely.
  • Singleton state leaks in long-running workers. PHP-FPM gives you a fresh process per request; RoadRunner, Swoole, Octane, and queue workers do not. If the correlation-ids package stores the ID statically, the previous request's ID will bleed into the next. Reset/clear it explicitly at the start (or end) of every request/job.
  • Null IDs when the processor runs before the ID is set. Registration order doesn't save you — if your bootstrap logs before the middleware runs, those lines carry null or an empty key. Put ID initialization as early as the framework allows.
  • Confirm the record key before touching your log pipeline. The processor may write to extra or context, and the exact sub-key name is the contract your log queries, index mapping, and formatter patterns depend on. Changing it later is a breaking change to dashboards.
  • Formatter patterns are finicky. %extra.correlation_id% will render blank (not error) if the key is spelled differently — you'll silently ship unusable logs. Assert once in a test that a log line contains a non-empty ID.
  • Test isolation. Static correlation state frequently bleeds between PHPUnit cases. Clear it in setUp()/tearDown() or tests will pass alone and fail in suite order.
  • Empty-ID noise. When no ID is available, default to - or omit the field entirely; a blank [] in every line trains people to ignore it.
  • Header naming is a cross-team contract. Standardize the inbound/outbound header (e.g., X-Correlation-ID) across all services before rollout. A mismatched header between two teams is the most common reason this "doesn't work" in production.
  • Extension points are minimal by design. This package is not where you customize — if you need multiple IDs, hashing, sampling, or trace-context interop, either subclass the processor or (better) write your own __invoke(array $record): array that returns $record with your fields added. It's the same code, without the abandoned dependency.
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.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk