Skip to content

Fix split-by-tags for tags configured by OpenTelemetry name - #12814

Open
dougqh wants to merge 2 commits into
masterfrom
dougqh/split-by-tags-canonical
Open

dougqh wants to merge 2 commits into
masterfrom
dougqh/split-by-tags-canonical

Conversation

@dougqh

@dougqh dougqh commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Fixes DD_TRACE_SPLIT_BY_TAGS for a tag that is configured by its OpenTelemetry name, for example db.system. When such a tag was set on the span builder, the service name was no longer split.

Motivation

Since #12354, TagMap.Entry construction canonicalizes OpenTelemetry names to Datadog names. A db.system tag set on the builder (or through default tags) is stored as db.type. TagInterceptor compared the canonical name with the configured db.system, so the two didn't match.

Span setters pass the raw name, so they kept working. The case mostly affects users of the OpenTelemetry API, because the bridge sets attributes on the builder.

Additional Notes

This is a short-term fix. At construction, the interceptor adds the Datadog name of each configured tag. The longer-term plan is to move TagInterceptor to id-based dispatch, which removes this whole category of name mismatch. That change will come in a separate PR.

The new test fails without the fix (the row configured by OTel name and set on the builder).

🤖 Generated with Claude Code

Entries set on the span builder are canonicalized to their Datadog name
(#12354), so a split-by-tags entry configured by its OpenTelemetry name
(e.g. db.system) no longer matched. Add the Datadog name of each
configured tag at load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh dougqh added comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM type: bug labels Oct 9, 2026
@dougqh
dougqh marked this pull request as ready for review October 9, 2026 14:17
@dougqh
dougqh requested a review from a team as a code owner October 9, 2026 14:17
@dougqh
dougqh requested review from jpbempel and removed request for a team October 9, 2026 14:17
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T14:19:46.390897Z ab3d841 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@datadog-prod-us1-3 datadog-prod-us1-3 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: PASS

More details

Canonical aliases allow builder and default tags to match OpenTelemetry-configured split tags while preserving the original spellings used by span setters. The completed static review identified no actionable regression.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit ab3d841

@datadog-prod-us1-3

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 13.97 s 13.92 s [-0.2%; +0.9%] (no difference)
startup:insecure-bank:tracing:Agent 12.81 s 12.93 s [-1.6%; -0.4%] (maybe better)
startup:petclinic:appsec:Agent 17.18 s 17.57 s [-6.7%; +2.3%] (no difference)
startup:petclinic:iast:Agent 17.32 s 17.46 s [-1.6%; +0.0%] (no difference)
startup:petclinic:profiling:Agent 17.45 s 17.31 s [-0.4%; +2.1%] (no difference)
startup:petclinic:sca:Agent 17.61 s 17.57 s [-0.7%; +1.2%] (no difference)
startup:petclinic:tracing:Agent 16.12 s 16.63 s [-7.3%; +1.2%] (no difference)

Commit: 73a0d4bc · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@bric3 bric3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the test should cover more cases, I asked codex to suggest a test that cover more ground.

Otherwise LGTM

Comment on lines +193 to +210
@TableTest({
"scenario | configured | tag ",
"configured by OTel name | db.system | db.system",
"configured by Datadog name | db.type | db.type ",
"Datadog name, set with OTel name | db.type | db.system"
})
void splitByTagsMatchesTheCanonicalNameOfABuilderTag(String configured, String tag) {
CoreTracer tracer = createSplittingTracer(configured);

AgentSpan builderSpan = tracer.buildSpan("datadog", "some span").withTag(tag, "split").start();
AgentSpan setterSpan = tracer.buildSpan("datadog", "some span").start();
setterSpan.setTag(tag, "split");

assertEquals("split", builderSpan.getServiceName());
if (configured.equals(tag)) {
assertEquals("split", setterSpan.getServiceName());
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Expand the inputs to cover the reverse alias pairing, custom and unconfigured tags, an empty configuration, both names already configured, and multiple renamed tags. This exercises the remaining branches in withCanonicalNames, including preserving custom tags when the set is copied.

Give the setter an explicit expected result: with db.type configured and db.system set, the builder splits but the setter keeps my-service. The conditional currently skips that assertion. The same rows can check default tags, which also arrive canonicalized.

Suggested change
@TableTest({
"scenario | configured | tag ",
"configured by OTel name | db.system | db.system",
"configured by Datadog name | db.type | db.type ",
"Datadog name, set with OTel name | db.type | db.system"
})
void splitByTagsMatchesTheCanonicalNameOfABuilderTag(String configured, String tag) {
CoreTracer tracer = createSplittingTracer(configured);
AgentSpan builderSpan = tracer.buildSpan("datadog", "some span").withTag(tag, "split").start();
AgentSpan setterSpan = tracer.buildSpan("datadog", "some span").start();
setterSpan.setTag(tag, "split");
assertEquals("split", builderSpan.getServiceName());
if (configured.equals(tag)) {
assertEquals("split", setterSpan.getServiceName());
}
}
@TableTest({
"scenario | configured | tag | expectedBuilder | expectedSetter",
"configured by OTel name | db.system | db.system | split | split ",
"configured by Datadog name | db.type | db.type | split | split ",
"Datadog config, OTel tag | db.type | db.system | split | my-service ",
"OTel config, Datadog tag | db.system | db.type | split | split ",
"custom tag | custom.tag | custom.tag | split | split ",
"unconfigured tag | db.system | other.tag | my-service | my-service ",
"empty configuration | '' | db.system | my-service | my-service ",
"both names, OTel tag | db.system,db.type | db.system | split | split ",
"both names, Datadog tag | db.system,db.type | db.type | split | split ",
"custom tag survives expansion | db.system,custom.tag | custom.tag | split | split ",
"first of two renamed tags | db.system,db.operation.name | db.type | split | split ",
"second of two renamed tags | db.system,db.operation.name | db.operation | split | split "
})
void splitByTagsMatchesCanonicalAndOriginalNames(
String configured, String tag, String expectedBuilder, String expectedSetter) {
injectSysConfig(SPLIT_BY_TAGS, configured);
CoreTracer tracer =
tracerBuilder()
.serviceName("my-service")
.writer(new LoggingWriter())
.sampler(new AllSampler())
.build();
AgentSpan builderSpan = tracer.buildSpan("datadog", "some span").withTag(tag, "split").start();
AgentSpan setterSpan = tracer.buildSpan("datadog", "some span").start();
setterSpan.setTag(tag, "split");
assertEquals(expectedBuilder, builderSpan.getServiceName());
assertEquals(expectedSetter, setterSpan.getServiceName());
CoreTracer defaultTagTracer =
tracerBuilder()
.serviceName("my-service")
.writer(new LoggingWriter())
.sampler(new AllSampler())
.defaultSpanTags(singletonMap(tag, "split"))
.build();
AgentSpan defaultTagSpan = defaultTagTracer.buildSpan("datadog", "some span").start();
assertEquals(expectedBuilder, defaultTagSpan.getServiceName());
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, applied in 73a0d4b. I kept the existing createSplittingTracer helper (now taking a set of tags plus default span tags) instead of injectSysConfig. All rows pass as written, including the setter keeping my-service for an OTel-name tag against Datadog-name config.

Written by Claude, reviewed by @dougqh

Cover reverse alias pairing, custom and unconfigured tags, empty
configuration, both names configured, multiple renamed tags, and
default span tags, with an explicit expected result for the setter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants