-
Notifications
You must be signed in to change notification settings - Fork 358
Propagate LLM Observability context across service boundaries #12416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ncybul
wants to merge
20
commits into
master
Choose a base branch
from
llmobs/sqs-context-propagation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
a66d66d
Propagate LLM Observability context across service boundaries
ncybul 4f08a5f
Propagate LLM Observability parent span id across service boundaries
ncybul 77546ab
Extract propagation tags from the _datadog message attribute
ncybul f26dec0
Update LLM Observability propagation tags as one atomic bundle
ncybul 3d9361f
Inline the LLM Observability tag map writes to match the surrounding …
ncybul d91534d
Apply review feedback: trim comments and group the LLMObs accessors
ncybul 5a58e5c
Reject LLMObs propagation tag values that x-datadog-tags cannot repre…
ncybul 0b3c363
Clear staged LLMObs propagation tags when no LLMObs context applies
ncybul 6e389d3
Resolve ml_app from the in-process parent and propagated context befo…
ncybul b474277
Override equals/hashCode on LLMObsTagValues instead of a bespoke sameAs
ncybul d6f6d3b
Drop the dead 7-arg LLMObsContext.attach overload and the redundant l…
ncybul 17780e8
Trim DatadogAttributeParserTest to the tag-forwarding case
ncybul bfa7670
Trim review comments per PR feedback
ncybul 30323f3
Preserve extracted LLMObs context when no local LLMObs span is active
ncybul ffc5015
Reject LLMObs tag values that no carrier can round-trip
ncybul 17cdcd6
Read LLMObs propagation tags from the extracted values, decoded
ncybul d726035
Consolidate the LLMObs propagation tests onto the existing helpers an…
ncybul f119b78
Compare trace IDs with equals instead of reference identity
ncybul 9944896
Trim redundant comments from DatadogAttributeParserTest
ncybul 8a4a379
Merge branch 'master' into llmobs/sqs-context-propagation
ncybul File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
...st/java/datadog/trace/bootstrap/instrumentation/messaging/DatadogAttributeParserTest.java
|
ncybul marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package datadog.trace.bootstrap.instrumentation.messaging; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| /** | ||
| * Covers the one behaviour this branch adds to the {@code _datadog} message attribute parser shared | ||
| * by the AWS messaging instrumentations (SQS, SNS, EventBridge, Step Functions): {@code | ||
| * x-datadog-tags} is forwarded to the extractor. | ||
| */ | ||
| class DatadogAttributeParserTest { | ||
|
|
||
| @Test | ||
| void forwardsPropagationTags() { | ||
| Map<String, String> collected = new LinkedHashMap<>(); | ||
| DatadogAttributeParser.forEachProperty( | ||
| (key, value) -> { | ||
| collected.put(key, value); | ||
| return true; | ||
| }, | ||
| "{\"x-datadog-trace-id\":\"1234567890\"," | ||
| + "\"x-datadog-parent-id\":\"9876543210\"," | ||
| + "\"x-datadog-sampling-priority\":\"1\"," | ||
| + "\"x-datadog-tags\":\"_dd.p.dm=-1,_dd.p.tid=6aa01c5400000000\"}"); | ||
|
|
||
| assertEquals("_dd.p.dm=-1,_dd.p.tid=6aa01c5400000000", collected.get("x-datadog-tags")); | ||
| } | ||
| } |
71 changes: 71 additions & 0 deletions
71
dd-java-agent/agent-llmobs/src/main/java/datadog/trace/llmobs/LLMObsContextPropagator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package datadog.trace.llmobs; | ||
|
|
||
| import datadog.context.Context; | ||
| import datadog.context.propagation.CarrierSetter; | ||
| import datadog.context.propagation.CarrierVisitor; | ||
| import datadog.context.propagation.Propagator; | ||
| import datadog.trace.api.llmobs.LLMObsContext; | ||
| import datadog.trace.bootstrap.instrumentation.api.AgentSpan; | ||
| import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; | ||
|
|
||
| /** | ||
| * Stages the LLM Observability propagation tags onto the span context being injected, so that every | ||
| * boundary already covered by automatic instrumentation carries LLMObs context without the | ||
| * application having to propagate it by hand. | ||
| * | ||
| * <p>This propagator writes nothing to the carrier itself. It runs ahead of the tracing propagator | ||
| * (see {@code AgentPropagation.LLMOBS_CONCERN}) and only populates the {@code _dd.p.llmobs_*} | ||
| * fields on the span context; the tracing propagator then serializes them into {@code | ||
| * x-datadog-tags} / {@code tracestate} along with every other propagation tag. | ||
| * | ||
| * <p>Values are resolved from the ambient {@link LLMObsContext} at injection time rather than being | ||
| * written once when a span starts, and every injection rewrites the whole set — falling back to | ||
| * whatever arrived on the inbound headers when no LLMObs context applies. That way the innermost | ||
| * active LLMObs span always wins, leaving an LLMObs scope stops contributing its tags, and a | ||
| * service that opens no LLMObs span of its own still forwards its caller's context — all without | ||
| * any save/restore bookkeeping. | ||
| */ | ||
| public class LLMObsContextPropagator implements Propagator { | ||
|
|
||
| @Override | ||
| public <C> void inject(Context context, C carrier, CarrierSetter<C> setter) { | ||
| AgentSpan span = AgentSpan.fromContext(context); | ||
| if (span == null) { | ||
| return; | ||
| } | ||
| AgentSpanContext spanContext = span.spanContext(); | ||
| if (spanContext == null) { | ||
| return; | ||
| } | ||
|
|
||
| // Gate on trace-id consistency, the same way DDLLMObsSpan gates parent_id/session_id | ||
| // inheritance. An LLMObs context leaked across an async boundary must not tag an outbound | ||
| // request that belongs to an unrelated trace. | ||
| AgentSpanContext llmObsContext = LLMObsContext.current(); | ||
| if (llmObsContext == null || !llmObsContext.getTraceId().equals(spanContext.getTraceId())) { | ||
| // Reset rather than return. These tags are staged on the root span context's propagation | ||
| // tags, which the whole local trace shares, so anything an earlier injection wrote would | ||
| // otherwise ride along on this one too — shipping a session and an agent attribution that | ||
| // are no longer active. Reset restores the extracted values instead of clearing outright: | ||
| // the same object also holds what came in on the wire, and a pass-through service must keep | ||
| // forwarding its caller's context. | ||
| spanContext.resetLLMObsContext(); | ||
| return; | ||
|
ncybul marked this conversation as resolved.
|
||
| } | ||
|
|
||
| spanContext.updateLLMObsContext( | ||
|
ncybul marked this conversation as resolved.
|
||
| LLMObsContext.currentMlApp(), | ||
| LLMObsContext.currentSessionId(), | ||
| LLMObsContext.currentParentAgentSpanId(), | ||
| LLMObsContext.currentParentAgentName(), | ||
| String.valueOf(llmObsContext.getSpanId())); | ||
| } | ||
|
|
||
| @Override | ||
| public <C> Context extract(Context context, C carrier, CarrierVisitor<C> visitor) { | ||
| // Nothing to do: the tracing propagator's codecs already parse the _dd.p.llmobs_* tags back | ||
| // into the extracted context's propagation tags, and DDLLMObsSpan reads them from there when | ||
| // no in-process LLMObs parent applies. | ||
| return context; | ||
|
ncybul marked this conversation as resolved.
|
||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.