Repository navigation
Export propagation tags in OTLP trace export - #12985
gh-worker-dd-mergequeue-cf854d[bot] merged 11 commits into
Conversation
The OTLP trace writers dropped the Metadata baggage map, which carries the propagation tags (_dd.p.dm, _dd.p.ksr, _dd.p.tid...) and baggage items injected as tags. Write it like the Datadog mappers do, with propagation tags on the local root span only, so the sampling decision maker reaches the Agent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
The OTLP traceId already carries all 128 bits, so the tag is redundant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A public Tags constant must be registered in the tag registry; the key is only needed by the OTLP writers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Both encoders can emit duplicate attribute keys when baggage collides with directly emitted span fields or metadata.
1 open issue
What changed in this PR
This PR adds propagation tags and baggage-as-tags to Java’s OTLP trace export, allowing downstream Agent processing to retain sampling decision metadata.
Changes:
- Serialize baggage and propagation tags in protobuf and JSON, with collision checks against span tags.
- Export propagation tags only on local roots and omit redundant
_dd.p.tid. - Add tests for sampling tags, inherited baggage, and root-only propagation tags.
| File | Description |
|---|---|
| dd-trace-core/src/test/java/datadog/trace/core/otlp/trace/OtlpTraceProtoTest.java | Adds protobuf export assertions and attribute parsing helpers. |
| dd-trace-core/src/test/java/datadog/trace/core/otlp/trace/OtlpTraceJsonCollectorTest.java | Adds JSON export assertions and span lookup helper. |
| dd-trace-core/src/main/java/datadog/trace/core/otlp/trace/OtlpTraceProto.java | Serializes baggage and root propagation tags into protobuf attributes. |
| dd-trace-core/src/main/java/datadog/trace/core/otlp/trace/OtlpTraceJson.java | Applies equivalent attribute serialization to JSON export. |
Review effort: Balanced
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Baggage collision filtering misses direction-dependent OTLP tag renames. With baggage injection and OTel semantics enabled, both encoders can emit conflicting server.port attributes instead of preserving the span's value.
🤖 Bits Code Review · Commit 6d518d3
mcculls
left a comment
There was a problem hiding this comment.
Added some proposed patches (drafted with codex) - once those are fixed then I'll re-review
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
With baggage injection enabled and OTel semantics disabled, alias-aware lookup in both OTLP encoders incorrectly suppresses baggage whose exported key differs from the span tag’s.
1 open issue
1 resolved since last review
Review effort: Balanced
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mcculls
left a comment
There was a problem hiding this comment.
Thanks for the refactoring!
|
Make sure to merge in latest |
…rt-propagation-tags
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
|
/merge |
|
View all feedbacks in Devflow UI.
PR already in the queue with status in_progress |

What Does This Do
Exports the span propagation tags (
_dd.p.dm,_dd.p.ksr, ...) and baggage-as-tags items as string attributes in OTLP trace export (protobuf and JSON), mirroring the Datadog mappers:OtlpTraceProto/OtlpTraceJsonMetaWriters now writeMetadata.getBaggage(), which was computed but never serialized. Span tags, and the attributes the writers emit directly (resource.name,operation.name,thread.name,_sampling_priority_v1, ...), win on a key clash, so OTLP attribute keys stay unique.ROOT_PROPAGATION_TAGS, read from the local root's context) are written once per trace in the payload, on the span the collector already selects for sampling tags (first exported span of a trace in protobuf, last in JSON). This covers partial flushes whose chunk has no local root span; other spans don't carry_dd.p.*. The Agent takes_dd.p.dmfrom the first span in a chunk that has it, so the carrier doesn't need to be the root._dd.p.tidis intentionally not exported: the OTLPtraceIdalready carries all 128 bits, and the Agent's OTLP receiver derives the upper 64 bits from it, so the tag would be redundant (Java generates 128-bit trace ids by default, so every root span would otherwise carry it). Same as the .NET change.Motivation
With
DD_TRACE_OTEL_EXPORTER=otlp, remote and adaptive sampling rules are applied (priority,_dd.rule_psrare exported), but the sampling decision maker_dd.p.dmnever was. The Agent then falls back to a default decision maker, so the backend doesn't count the traffic as rule/adaptive-sampled and adaptive sampling can't converge for the service.This complements DataDog/datadog-agent#58471, which preserves
_dd.p.dmfrom OTLP span attributes (ort.dmfrom a tracestatedd=member). The .NET equivalent is DataDog/dd-trace-dotnet#9498.Additional Notes
_dd.p.dm:-4; with this change the exported trace is expected to carry the rule's decision maker (-11remote user rule /-12remote adaptive rule), which the Agent keeps with [trace-agent] Preserve tracer sampling decision maker in OTLP receiver datadog-agent#58471. The end-to-end run with this exact build is still to do.OtlpTraceProtoTestandOtlpTraceJsonCollectorTest:propagationTagsAreWrittenOncePerTraceOnTheSpanSelectedForSamplingTags,partialFlushWithoutTheLocalRootStillCarriesPropagationTagsandpropagationTagsAreWrittenOnceForEachTraceInThePayloadcheck exactly one copy of_dd.p.dm/_dd.p.ksrper trace, on the selected span, no_dd.p.tid, and baggage on every span;baggageDoesNotDuplicateDirectlyWrittenAttributesin both checks that baggage items named like directly emitted attributes don't duplicate them.:dd-trace-core:spotlessCheckcouldn't run locally because the Eclipse p2 site used by the Groovy formatter was down; changed files were checked with google-java-format 1.36.1.dd=tracestate member, so the OTLPtrace_statedoesn't carryt.dm.Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issueJira ticket: N/A
🤖 Generated with Claude Code