PHPackages                             niladam/laravel-tracing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. niladam/laravel-tracing

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

niladam/laravel-tracing
=======================

W3C Trace Context for Laravel: one id follows a request through its logs, its queued jobs and the services it calls.

v2.0.0(today)22↑2900%MITPHPPHP ^8.2CI passing

Since Aug 24Pushed todayCompare

[ Source](https://github.com/niladam/laravel-tracing)[ Packagist](https://packagist.org/packages/niladam/laravel-tracing)[ Docs](https://github.com/niladam/laravel-tracing)[ RSS](/packages/niladam-laravel-tracing/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (12)Versions (3)Used By (0)

[![Laravel Tracing](https://raw.githubusercontent.com/niladam/laravel-tracing/main/docs/logo.jpg)](https://raw.githubusercontent.com/niladam/laravel-tracing/main/docs/logo.jpg)[![A request traced through its jobs and the services they call, every log line carrying the same trace id](https://raw.githubusercontent.com/niladam/laravel-tracing/main/docs/header.jpg)](https://raw.githubusercontent.com/niladam/laravel-tracing/main/docs/header.jpg)

[![Latest Version on Packagist](https://camo.githubusercontent.com/5e4af3ac633adba3d4a5e7395d02b70050355328487defc85c6c87a21b875669/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e696c6164616d2f6c61726176656c2d74726163696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/niladam/laravel-tracing)[![Tests](https://camo.githubusercontent.com/5910f0675a12ff3643d649345c633d3a4dc4df881788cb93d8b5045bb177ed06/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e696c6164616d2f6c61726176656c2d74726163696e672f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/niladam/laravel-tracing/actions/workflows/run-tests.yml)[![Code Style](https://camo.githubusercontent.com/b9542d297a3bac149f774e651bdbf000766345299ba06d74b70b831192f79228/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e696c6164616d2f6c61726176656c2d74726163696e672f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/niladam/laravel-tracing/actions/workflows/fix-php-code-style-issues.yml)[![Total Downloads](https://camo.githubusercontent.com/0815c456a53240be59b0e9cfbc5b802223eff2f13975063c7f4c68edb710b93a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6e696c6164616d2f6c61726176656c2d74726163696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/niladam/laravel-tracing)

One id follows a request through its own log lines, the queued jobs it dispatches, the jobs *those* dispatch, and the internal services it calls.

Built on the [W3C Trace Context](https://www.w3.org/TR/trace-context/) standard, so it speaks the same `traceparent` header as OpenTelemetry, Sentry, Datadog and Honeycomb — no APM dependency required, and nothing to rewrite if you add one later.

`grep` one `trace_id` for the whole tree. `parent_span_id` tells you who triggered what.

Installation
------------

[](#installation)

```
composer require niladam/laravel-tracing
```

That is the whole setup — the provider is auto-discovered, requests are traced, jobs inherit the trace and log lines carry it. Publish the config only when you want to change something:

```
php artisan vendor:publish --tag=laravel-tracing-config
```

What you get without configuring anything
-----------------------------------------

[](#what-you-get-without-configuring-anything)

Key`trace_id`32 hex. The root, minted once at the origin and **never** regenerated as it travels.`span_id`16 hex. This one unit of work — this request, this job run, this command.`parent_span_id`The `span_id` that caused this one. `null` at the root.`channel``http`, `console` or `queue`.`user_id`The moment any guard answers — session and stateless alike.`ip`, `url`, `method`On a request.`command`On a console command.`job.*``name`, `connection`, `queue`, `attempts`, `uuid` — inside a job.Crossing every boundary on the way:

BoundaryHowInbound HTTPReads `traceparent` / `tracestate` and continues the caller's traceQueued jobsContext dehydrate/hydrate, with a fresh child span per job runConsole subprocessesLaravel rehydrates `__LARAVEL_CONTEXT`, so `Artisan::call` children join inOutgoing HTTP`traceparent` injected on your own hosts only — never a third partySaloonRegistered separately, since it ships its own sender. Optional.LogsMerged into each record's `context`, so a line stays one JSON objectAdding your own context
-----------------------

[](#adding-your-own-context)

Every key has a **moment** — the instant it becomes true. Record it then and you never think about middleware order or whether the user has logged in yet.

Pick the lightest rung that fits:

Your key is…Do thisa constant`context.additional` in config — no codea value or two, computed`Tracing::always(…)`tied to who is logged in`Tracing::authenticated('web', …)`tied to a moment`Tracing::on(SomeEvent::class, …)`growing, or needs dependenciesa `Recorder` class listed in `record````
use Niladam\LaravelTracing\Facades\Tracing;

// in a service provider's boot()
Tracing::always(fn () => ['host' => gethostname()]);

Tracing::authenticated('web', fn (User $user) => [
    'team_id' => $user->current_team_id,
]);

Tracing::on(TeamSwitched::class, fn ($e) => ['team_id' => $e->team->id]);
```

That last line is the part a middleware cannot do: `Context::add` overwrites, so the key **corrects itself** the moment the team changes. Snapshot it once at the start of a request and it is wrong for the rest of it.

Anything you put in Laravel's own `Context` is traced too — there is no second store and nothing new to learn:

```
Context::add(['order_id' => $order->id]);
Context::addHidden('idempotency_key', $key);   // travels to jobs, never logged
```

Read the trace back through the facade, which knows what you have named the keys:

```
Tracing::traceId();       // 4bf92f3577b34da6a3ce929d0e0e4736
Tracing::traceparent();   // to hand to a client this package does not cover
```

Keeping secrets out
-------------------

[](#keeping-secrets-out)

Four mechanisms, narrowest first — [the guide](docs/secrets.md) covers which to reach for:

```
#[\SensitiveParameter] public string $cardToken,             // never recorded at all
Context::addHidden('key', $value);                           // travels, never logged
'logs'    => ['redact' => ['keys' => ['*password*']]],       // safety net, descends into nested values
'context' => ['local_only' => ['body.*']],                   // stays in this process, never written to your queue
```

Documentation
-------------

[](#documentation)

[Recording context](docs/recording-context.md)The moments, the built-in recorders, and plugging in your own[Adding your own context](docs/adding-context.md)Using Laravel's `Context` — anywhere, any time, including mid-job[Registering the middleware](docs/middleware.md)Groups, global, or a route alias — plus ordering and manual wiring[Jobs](docs/jobs.md)Child spans, `job.*` context, and opt-in job arguments[Keeping secrets out](docs/secrets.md)`#[\SensitiveParameter]`, hidden context, redaction, and your queue[Handing the trace back](docs/response-headers.md)Response headers, and showing an id to a user[Interoperability](docs/interoperability.md)The wire format, renaming keys, upstream ids, Saloon, APMsConfiguration at a glance
-------------------------

[](#configuration-at-a-glance)

Five groups, each answering one question:

```
'middleware'  => [...],   // where a trace begins
'record'      => [...],   // what gets recorded
'context'     => [...],   // what lands in the context
'logs'        => [...],   // what reaches a log line
'propagation' => [...],   // what leaves the application
```

`'enabled' => false` turns the lot off.

Requirements
------------

[](#requirements)

PHP8.2+ (8.3+ on Laravel 13)testedLaravel 12`^12.1`testedLaravel 13`^13.0`testedSaloon`^4.0`, optionaltested, and tested absentThe floors are where the APIs this package needs first appeared, nothing more. Keeping your framework patched is your application's business and `composer audit`'s — a package that pins a security floor only goes stale on the next advisory.

### Why not Laravel 11

[](#why-not-laravel-11)

`Illuminate\Contracts\Log\ContextLogProcessor` arrived in **v12.1.0** — it exists in no Laravel 11 release. Without it there is no supported way to put the trace on a log record, which is most of what this package does, so Laravel 11 is not a matter of testing effort: there is nothing to hook into. That is also why the Laravel 12 floor is `^12.1` rather than `^12.0`.

Saloon v3 is unsupported for a different reason: every release carries an unpatched advisory (`
