Repository navigation
Conversation
When exporting traces over OTLP, write the trace's global tags (DD_TAGS, leftover OTEL_RESOURCE_ATTRIBUTES, or the remote config tracing_tags override) once as resource attributes, taken from the settings snapshot the trace was created with, and skip span string tags with the same key and value. Chunks that produce different resource attributes are written under separate ResourceSpans in the same payload. 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.
More details
Resource grouping and rejected-chunk handling appear consistent with keeping each trace’s global-tag snapshot attached to its spans. This assessment is based on source inspection; runtime behavior was not exercised.
🤖 Bits Code Review · Commit 9b3c8ac
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (9596) and master. ✅ No regressions detected |
BenchmarksBenchmark execution time: 2026-11-02 22:44:58 Comparing candidate commit 9b3c8ac in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 72 metrics, 0 unstable metrics, 3 known flaky benchmarks, 122 flaky benchmarks without significant changes.
|
Summary of changes
When traces are exported over OTLP (
OTEL_TRACES_EXPORTER=otlp, JSON or protobuf), global tags (DD_TAGS, leftoverOTEL_RESOURCE_ATTRIBUTES, or the remote configtracing_tagsoverride) are now written once as OTLP resource attributes instead of being repeated as attributes on every span. Span tags that differ from the global value (span-level overrides) are kept on the span. MessagePack export and in-memory span tags are unchanged.Reason for change
The OTLP trace resource carried no global tags, and every span repeated them as attributes. This makes payloads bigger and models process-wide attributes incorrectly for OpenTelemetry backends. Same change in other SDKs: DataDog/dd-trace-java#13065, DataDog/dd-trace-go#5718, DataDog/dd-trace-js#10886.
Implementation details
OtlpResourceGlobalTags.FromTraceChunkreadsTraceContext.CurrentTraceSettings.Settings.GlobalTags, not the tracer's latest settings. After atracing_tagsRC change, in-flight traces keep their old resource and new traces get the new one, so the resource is never stale (unlike the static resource in Go/JS).OtlpResourceGlobalTagsis cached perGlobalTagsdictionary (ConditionalWeakTable; dictionaries are replaced, not mutated). Keys stay on spans if they are:service/env/versionand their OTel names,telemetry.sdk.*,runtime-id,git.*,datadog.sdk.semantics);Span.SetTagor span-level (sampling.priority,manual.keep/manual.drop,peer.service,error.*,span.kind,component, ...);_dd*) or Azure App Service tags (aas.*);ITagsproperties that a span doesn't export as the same string (dual DD/OTel names likehttp.method/http.request.method, non-string likeserver.port); a test fails if a new such property is added without updating the list;OtlpMapper.TagWriterskips a string span tag when the resource has the same key and value, before the 128-attribute limit is counted. Metrics are never deduplicated.OtlpResourceIdentityholds the resource inputs.OtlpResourceSpansGroups, shared by both serializers, opens a newResourceSpansinside the same payload when a chunk's resource differs from the current one. A chunk thatSpanBufferserialized but didn't keep is dropped from this state. The protobuf serializer patches every group's length placeholders inFinishBody. Flushing is unchanged. (dd-trace-java flushes the payload instead.)TraceChunkModelis unchanged.Known behavior changes (release notes):
region,zone,pod_name,kube_namespace, ...) are consumed by the Agent'sConsumeContainerTagsFromResourceas container tags. They remain searchable as tags (region:us1) but no longer appear as a span attribute (@region).Known gaps / follow-ups:
Tracer.StartSpancopies global tags fromCurrentTraceSettings(active scope's trace, or latest settings), not the new span's ownTraceContextsnapshot. In rare cases (explicit parent from another trace, or an RC update racing a root span), a span's tags and its chunk's resource come from different snapshots, and the global values stay on the span.service.nameon the resource still comes from the tracer's latest settings, not the trace's snapshot.Test coverage
New
OtlpResourceAttributesTests(JSON and protobuf, OTel semantics on/off where relevant):ResourceSpans(us1,eu1,us1); equivalent tags share one;http.methodon anHttpTagsspan) stay on the span only; a reflection-based drift test over[Tag]properties;OtlpResourceGlobalTags.Ran locally on net11.0:
OtlpResourceAttributesTests,OtlpTracesJsonSerializerTests,OtlpTracesProtobufSerializerTests,OtlpMapperTests,SpanBufferTests,TraceChunkModelTests: 231 passed.Other details
APMAPI-2309. Supersedes the test-only draft #9526.
🤖 Generated with Claude Code