Skip to content

fix(observability): extract upstream traceparent, re-parent server span, and inject traceparent on egress#159

Open
gyliu513 wants to merge 2 commits into
llm-d:mainfrom
gyliu513:trace
Open

fix(observability): extract upstream traceparent, re-parent server span, and inject traceparent on egress#159
gyliu513 wants to merge 2 commits into
llm-d:mainfrom
gyliu513:trace

Conversation

@gyliu513

Copy link
Copy Markdown
Member

What type of PR is this?

/kind feature

What this PR does / why we need it:

IPP runs as an Envoy ext_proc filter, sequentially on the same Envoy HTTP filter chain as EPP. Like EPP (fixed in llm-d/llm-d-router#1514), IPP started its server span at the top of Process() before the request headers were received, so it never extracted the upstream traceparent and started a new root trace per request.

In addition, unlike EPP, IPP did not inject traceparent on egress: it already has a HeaderMutation pipeline, but trace context was never written into it, so a downstream ext_proc filter in the chain could not see IPP's span as its parent.

Which issue(s) this PR fixes:

Fixes #157

Release note (write NONE if no user-facing change):

IPP now extracts the upstream trace context from request headers and re-parents its server span to it, and injects `traceparent` into the egress header mutation so downstream ext_proc filters join the same trace.

@github-actions github-actions Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. kind/feature Categorizes issue or PR as related to a new feature. labels Jun 12, 2026
Comment thread pkg/handlers/request.go

// Inject the active trace context into the egress headers so the next
// filter in the chain is parented to this span rather than the upstream one.
traceCarrier := propagation.MapCarrier{}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to normalize headers from the tracecarrier as LC, as a "just in case"? 🤔

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, it's a no-op for the default W3C propagator (traceparent/tracestate are already lowercase), but SetHeader writes the key verbatim into the Envoy header mutation, and over HTTP/2 a non-W3C/custom propagator could emit mixed-case keys.

Lowercasing is cheap defensive insurance, so I've normalized the carrier keys with strings.ToLower.

Comment thread pkg/handlers/request.go
for key, value := range traceCarrier {
// Normalize keys to lowercase; HTTP/2 (used by ext_proc) requires
// lowercase header names, and a non-W3C propagator may emit mixed case.
reqCtx.Request.SetHeader(strings.ToLower(key), value)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause duplicate keys, differenciated only by their case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shmuelk , I will normalize incoming header keys to lowercase at ingestion

gyliu513 added 2 commits June 18, 2026 12:04
…an, and inject traceparent on egress

Signed-off-by: Guangya Liu <gyliu513@gmail.com>
Signed-off-by: Guangya Liu <gyliu513@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[observability] IPP: extract upstream traceparent at ext_proc ingress, re-parent span, and inject traceparent on egress

3 participants