Skip to content

feat(tracing): adopt an edge's trace id without parenting its span - #66

Merged
sylvesterdamgaard merged 1 commit into
mainfrom
feat/edge-injected-traceparent
Oct 1, 2026
Merged

sylvesterdamgaard merged 1 commit into
mainfrom
feat/edge-injected-traceparent

Conversation

@sylvesterdamgaard

Copy link
Copy Markdown
Contributor

Load balancers and proxies often inject a traceparent on every request, so their access log carries a trace id that joins the backend's trace, while exporting no span of their own. Continuing that header makes every request span the child of a span that never arrives, and trace backends list those traces as missing their root. We hit this in production behind HAProxy: every app trace in Tempo showed up as "root span not yet received".

What changes

  • New traces.continue_incoming_parent (TELEMETRY_TRACES_CONTINUE_INCOMING_PARENT), default true. With the default, nothing changes.
  • Set to false, the request adopts the incoming trace id and sampled flag (still subject to trust_incoming_sampling) but starts as the root span. The span id the edge named is kept as a span link instead of a parent, so the edge's log line still joins the trace and the reference isn't silently dropped.
  • Tracer::adoptTraceId() sits next to continueFrom(); TraceRequest picks between them.
  • AGENTS.md invariant 5 ("children, never detached roots") now names this opt-in exception.

Tests

Three new cases in RequestInstrumentationTest:

  • the trace id is adopted with no parent and a link to the edge span
  • an unsampled incoming flag is still respected
  • with no header, the span is a plain root with no link

composer check is green (Pint, PHPStan, full suite).

Docs

  • traces.md has a new "Behind an edge that injects traceparent" section.
  • Also updated: the config reference, the AI guidelines, llms.txt and the CHANGELOG (Unreleased/Added).

Load balancers and proxies often inject a traceparent on every request
so their access log joins the backend's trace, while exporting no span of
their own. Continuing that header made every request span the child of a
span that never arrives, and trace backends listed those traces as
missing their root.

traces.continue_incoming_parent (default true, so behaviour is unchanged)
turns that off: the request adopts the incoming trace id and sampled
flag, starts as the root span, and links the span id the edge named. The
trace id is kept so the edge's log still joins, and the reference is kept
as a link rather than dropped.
@sylvesterdamgaard
sylvesterdamgaard force-pushed the feat/edge-injected-traceparent branch from b07d2c4 to 3be0484 Compare October 1, 2026 20:30
@sylvesterdamgaard
sylvesterdamgaard merged commit 245a6a1 into main Oct 1, 2026
16 checks passed
@sylvesterdamgaard
sylvesterdamgaard deleted the feat/edge-injected-traceparent branch October 1, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant