feat(llmobs): propagate session_id to following spans and across services [MLOB-7756]#9279
Conversation
…ices The first session_id set in a trace is stored on the trace-shared propagating tags (_dd.p.llmobs_session_id). Later spans - including those under a session-less parent and spans in downstream services - inherit it, and it rides x-datadog-tags across service boundaries via the standard propagator. An explicit session_id still overrides locally. MLOB-7756 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Overall package sizeSelf size: 6.71 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.1 | 122.62 kB | 437.94 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-07-10 21:07:26 Comparing candidate commit ac05921 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 2324 metrics, 34 unstable metrics.
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: ac05921 | Docs | Datadog PR Page | Give us feedback! |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9279 +/- ##
==========================================
- Coverage 96.57% 96.57% -0.01%
==========================================
Files 918 918
Lines 121521 121579 +58
Branches 21089 20993 -96
==========================================
+ Hits 117355 117411 +56
- Misses 4166 4168 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Matches the wire contract agreed in dd-trace-py#18952: keep the llmobs_ namespace, shorten session_id -> sid to conserve x-datadog-tags budget. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: afae342a84
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…registration Move the trace-level default establishment into _setTag, the single choke point for session writes, so sessions post-populated by integrations after span start (e.g. claude-agent-sdk's _setTag(span, SESSION_ID, ...)) also seed the trace default. First-writer wins, so an explicit session still overrides. Addresses review feedback on #9279. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ices [MLOB-7756] (#9279) * feat(llmobs): propagate session_id to following spans and across services The first session_id set in a trace is stored on the trace-shared propagating tags (_dd.p.llmobs_session_id). Later spans - including those under a session-less parent and spans in downstream services - inherit it, and it rides x-datadog-tags across service boundaries via the standard propagator. An explicit session_id still overrides locally. MLOB-7756 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * refactor(llmobs): shorten propagated session key to _dd.p.llmobs_sid Matches the wire contract agreed in dd-trace-py#18952: keep the llmobs_ namespace, shorten session_id -> sid to conserve x-datadog-tags budget. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * fix(llmobs): establish trace-default session in _setTag, not just at registration Move the trace-level default establishment into _setTag, the single choke point for session writes, so sessions post-populated by integrations after span start (e.g. claude-agent-sdk's _setTag(span, SESSION_ID, ...)) also seed the trace default. First-writer wins, so an explicit session still overrides. Addresses review feedback on #9279. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…ices [MLOB-7756] (#9279) * feat(llmobs): propagate session_id to following spans and across services The first session_id set in a trace is stored on the trace-shared propagating tags (_dd.p.llmobs_session_id). Later spans - including those under a session-less parent and spans in downstream services - inherit it, and it rides x-datadog-tags across service boundaries via the standard propagator. An explicit session_id still overrides locally. MLOB-7756 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * refactor(llmobs): shorten propagated session key to _dd.p.llmobs_sid Matches the wire contract agreed in dd-trace-py#18952: keep the llmobs_ namespace, shorten session_id -> sid to conserve x-datadog-tags budget. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * fix(llmobs): establish trace-default session in _setTag, not just at registration Move the trace-level default establishment into _setTag, the single choke point for session writes, so sessions post-populated by integrations after span start (e.g. claude-agent-sdk's _setTag(span, SESSION_ID, ...)) also seed the trace default. First-writer wins, so an explicit session still overrides. Addresses review feedback on #9279. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
What
Propagates LLMObs
session_idso it reaches the spans that follow it in a trace — including spans under a session-less parent and spans in downstream services.The first
session_idset in a trace is stored on the trace-shared propagating tags as_dd.p.llmobs_sid. Later spans inherit it (via the tagger's resolution fallback), and it ridesx-datadog-tagsacross service boundaries via the standard propagator's_dd.p.*inject/extract. An explicitsession_idon a span still overrides locally, so multiple sessions can still coexist in one trace.Mirrors the dd-trace-py change in dd-trace-py#18952 and the same
_dd.p.llmobs_*propagation pattern already used forml_app.Changes
packages/dd-trace/src/llmobs/constants/tags.js— addPROPAGATED_SESSION_ID_KEY(_dd.p.llmobs_sid).packages/dd-trace/src/llmobs/tagger.js— resolvesession_idfrom explicit arg → parent → trace default; establish the trace default on_trace.tags(first-writer). Noindex.jsinject change needed:_injectTagsalready propagates any_dd.p.*trace tag.packages/dd-trace/test/llmobs/tagger.spec.js— tests for establishing the default, sibling-gap inheritance, and explicit override not clobbering the default.Test plan
Simulating a distributed session (trace)
Simulating default session being applied to subsequent spans in a trace unless explicitly annotated (trace)
session_id:my-sessionwhich is inherited by subsequent spans except those explicitly annotated withsession_id:other-sessionMLOB-7756