Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
3ab5862
Set known tags by id on TagMap and spans
dougqh Oct 9, 2026
4bf02bb
Ignore unknown ids when clearing a tag by id; fix a comment wrap
dougqh Oct 9, 2026
a2829d1
Precheck and reuse the box in long-valued setters
dougqh Oct 9, 2026
2d87cde
Keep peer.port off the id path
dougqh Oct 9, 2026
7a017a5
Merge set-by-id (#12715) onto master
dougqh Oct 9, 2026
0401a43
Mark intercepted tags with an id bit, via a tracer overlay
dougqh Oct 9, 2026
8949a57
Dispatch TagInterceptor on tag ids
dougqh Oct 9, 2026
cfe2368
Set tags on spans by id first
dougqh Oct 9, 2026
38c9947
Look up tag names by serial in an array, not a switch
dougqh Oct 9, 2026
3545c15
Point stale comments at the tracer overlay and the intercepted bit
dougqh Oct 9, 2026
1642cc9
Index the split-by-tags table by serial, sized to every known tag
dougqh Oct 9, 2026
b9dd573
Check for a known tag id with a range check, not a name lookup
dougqh Oct 9, 2026
75d3fbc
Pin interceptTag(long) above C2's inlining size
dougqh Oct 9, 2026
ecb4f73
Tighten comments on the id-keyed interceptor
dougqh Oct 9, 2026
3f65031
Treat overlay tags as intercepted; tidy from review
dougqh Oct 9, 2026
69d7849
Reject shared-name tag ids on the id-keyed TagMap and span paths
dougqh Oct 9, 2026
46c3b47
Test rejection of shared-name tag ids
dougqh Oct 9, 2026
ad2fa97
Build custom tags by name and known tags by id
dougqh Oct 10, 2026
3a269e1
Resolve direction-dependent tag names by the span's kind
dougqh Oct 9, 2026
d509119
Key shared-name tags by direction now that resolution knows it
dougqh Oct 10, 2026
628da33
Merge master into id-tag-interceptor (#12817)
dougqh Oct 10, 2026
cc43136
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 10, 2026
dac7060
Give the tracer core a restricted, trusted path into TagMap
dougqh Oct 10, 2026
fbab551
Mark TagMap.Internals @NoEscape
dougqh Oct 10, 2026
8d47c7f
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 10, 2026
92fb191
Point Internals' trust note at isKnown, the span's check here
dougqh Oct 10, 2026
06dec0f
Store each direction-dependent tag once and apply direction on read
dougqh Oct 13, 2026
d469c66
Name direction-dependent tags by span kind in OTLP export
dougqh Oct 13, 2026
748a8af
Apply last write wins between a tag and its direction-scoped alias
dougqh Oct 13, 2026
44826c6
Carry the direction role in tag ids so plain setTag pays nothing extra
dougqh Oct 13, 2026
dc06725
Move alias superseding off the setTag store fast path
dougqh Oct 13, 2026
44c9c2f
Cover SpanTags and the KnownTagCodec direction helpers in internal-api
dougqh Oct 13, 2026
d3d6ee4
Route alias-target writes only on spans holding a pending alias
dougqh Oct 13, 2026
a48e145
Merge tag-registry-direction-resolution into the single-representatio…
dougqh Oct 13, 2026
85c222d
Cover the remaining TagMap.Internals setKnown overloads
dougqh Oct 13, 2026
f08c1c3
Add datadog.apicontract to CODEOWNERS
dougqh Oct 13, 2026
f796149
Merge branch 'master' into dougqh/id-tag-interceptor
dougqh Oct 13, 2026
22d0fd1
Give peer.port one direction-neutral id
dougqh Oct 13, 2026
ba715de
Name peer.port by the span's kind in OTLP export
dougqh Oct 13, 2026
e55a358
Merge id-tag-interceptor (#12817, before the peer.port move) into tag…
dougqh Oct 13, 2026
01ea7f5
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 13, 2026
584310c
Let C2 inline the constructors of TagMap's nested classes
dougqh Oct 11, 2026
3842b16
Remove TagMap's remaining synthetic accessors and guard against them
dougqh Oct 11, 2026
6e6077e
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 13, 2026
64d6cf3
Merge master into id-tag-interceptor
dougqh Oct 14, 2026
bb0bbb0
Cover TagMap.Internals, KnownTagCodec and EntryReader paths
dougqh Oct 14, 2026
fb6410e
Format the tag-registry generator to its spotless rules
dougqh Oct 14, 2026
6593371
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 14, 2026
0d7b732
Drop #12817's direction stand-in tests, covered by SpanTagsTest
dougqh Oct 14, 2026
97a508b
Order the tag-id carve bits by position
dougqh Oct 14, 2026
fa54aca
Merge master into id-tag-interceptor
dougqh Oct 14, 2026
4bb2c75
Merge id-tag-interceptor (#12817) into tag-registry-direction-resolution
dougqh Oct 14, 2026
1c88d5e
Re-apply split-by-tags language by its id
dougqh Oct 14, 2026
5ba0a09
Say what a tag id's intercepted bit does and doesn't decide
dougqh Oct 14, 2026
1a084b2
Merge #12817's final commits into tag-registry-direction-resolution
dougqh Oct 15, 2026
a24cb0d
Merge remote-tracking branch 'origin/master' into dougqh/tag-registry…
dougqh Oct 15, 2026
32ad2a3
Restore the conventions' one-tag wording for peer.port
dougqh Oct 15, 2026
306b312
Tidy the direction-resolution code from review
dougqh Oct 15, 2026
96df27a
Keep the alias slow paths to spans that really hold a pending alias
dougqh Oct 15, 2026
a5c6556
Make a removal before the span's kind supersede every meaning
dougqh Oct 15, 2026
d7356bc
Extend the pending-alias gate to reads, removals and entry routing
dougqh Oct 15, 2026
c517b18
Encapsulate direction handling in a package-private DirectionalTags
dougqh Oct 15, 2026
ab4b1ac
Write and read known tags by id without building an Entry per call
dougqh Oct 16, 2026
351145d
Resolve aliases when the kind is set, and route them as their tag
dougqh Oct 16, 2026
6aa6d4f
Close three more gaps between the write paths and direction handling
dougqh Oct 16, 2026
1c92947
Split TagMap into a view over an id store and a name store
dougqh Oct 16, 2026
4d6f7d0
Route TagMap's name-keyed operations through one resolver
dougqh Oct 16, 2026
d2261f3
Clarify what the store split costs and where a dense mode would plug in
dougqh Oct 16, 2026
e605c60
Let the span own its tag stores and route to them directly
dougqh Oct 16, 2026
7d80723
Add a benchmark of reading tags back from a live span
dougqh Oct 16, 2026
5f7458b
Copy tracer-level tags into a span's store without a view
dougqh Oct 16, 2026
ac7a00d
Cache the span's view of its tag stores
dougqh Oct 16, 2026
2d0ef38
Keep a span's pending aliases in their own holder
dougqh Oct 16, 2026
f7999bd
Color known tags into co-occurrence slots in their ids
dougqh Oct 15, 2026
0475a1f
Treat a custom tag's zero id as unslotted
dougqh Oct 15, 2026
8ed88c9
Say a slot bit is only a may-be-present signal
dougqh Oct 15, 2026
31bf06e
Give known and custom tags separate hash stores
dougqh Oct 16, 2026
d147b3d
Measure a read of a known tag the span doesn't hold
dougqh Oct 16, 2026
023313b
Let the span use its tag stores directly again
dougqh Oct 16, 2026
cd501d5
Note why the span's custom-store flag needs no volatile
dougqh Oct 16, 2026
08d769f
Register the tracer's root-span tags as known tags
dougqh Oct 16, 2026
aa324be
Pass DirectionalTags the span's stores instead of the span
dougqh Oct 16, 2026
dabddda
Let a Datadog tag name double as another tag's direction-scoped alias
dougqh Oct 16, 2026
b1107a3
Drop the OTLP export check for a tag written by id on the wrong side
dougqh Oct 16, 2026
1bf3e28
Keep pending aliases out of TagInterceptor
dougqh Oct 16, 2026
3b9cc8d
Hand the span's view its direction instead of the span
dougqh Oct 16, 2026
66a069c
Merge remote-tracking branch 'origin/master' into dougqh/tag-registry…
dougqh Oct 16, 2026
d7f0ffc
Resolve direction-scoped names at the OpenTelemetry boundary, not in …
dougqh Oct 16, 2026
f746fbe
Look up known tags by id, not by name, in the id store
dougqh Oct 16, 2026
2d56d29
Average known-tag reads over the span's tags in GetTagBenchmark
dougqh Oct 16, 2026
7547659
Return EntryReader from IdStore's point operations
dougqh Oct 16, 2026
df09039
Generate a serial-to-id table so a store can keep only the serial
dougqh Oct 16, 2026
a31a1de
Add a dense id store behind an experimental flag
dougqh Oct 16, 2026
462f753
Read a root span's trace-level tags through one shared parent
dougqh Oct 17, 2026
634e880
Keep span-level and trace-level slot bits apart with a level set
dougqh Oct 17, 2026
463ffb2
Merge #12731: direction handling moves to the OpenTelemetry boundary
dougqh Oct 17, 2026
030fc85
Address review: IdStore naming, EntryReader puts, member order
dougqh Oct 17, 2026
6bcd11f
Clarify comments touched by the store split
dougqh Oct 17, 2026
4e6ead4
Rename newEmpty to createEmpty
dougqh Oct 17, 2026
4d77117
Fold TagRouting into its users
dougqh Oct 17, 2026
f634ec7
Address review: knownTags, GuardedBy and the span's locking scheme
dougqh Oct 17, 2026
da19019
Drop the span's cached view instead of re-attaching it
dougqh Oct 17, 2026
9a5583f
Prefix the span's store-routing operations with route
dougqh Oct 17, 2026
2ed6e5f
Fold EntryReadingHelper into the dense store's reader
dougqh Oct 17, 2026
a722412
Rename TagMap's stores to knownStore and nameStore
dougqh Oct 17, 2026
14f33ca
Drop two per-call allocations from the review
dougqh Oct 17, 2026
334e26a
Tidy the store split from review
dougqh Oct 17, 2026
3a09000
Remove TagMap.getKnownValue
dougqh Oct 17, 2026
fff066e
Fix misplaced and stale comments from review
dougqh Oct 17, 2026
0f1e5ac
Keep one occupancy word per level in the id store
dougqh Oct 17, 2026
416663b
Merge master (#12882 slot coloring) into tag-registry-direction-resol…
dougqh Oct 19, 2026
77c7445
Merge tag-registry-direction-resolution (master's #12882) into tagmap…
dougqh Oct 19, 2026
b306324
Cover both id stores with a shared contract test
dougqh Oct 19, 2026
ac96cd7
Keep the no-entry reader no-op, and make makeTagId the real id
dougqh Oct 20, 2026
eee2c9c
Give point reads their own Entry instead of the store's shared reader
dougqh Oct 20, 2026
24a64df
Merge master (#12731, #12893) into dougqh/tagmap-split-stores
dougqh Oct 20, 2026
018a273
Read known tag values straight from the store in getObject and getString
dougqh Oct 20, 2026
33badb1
Add TagMap.getEntryReader and route the primitive getters through it
dougqh Oct 20, 2026
f7cdf1c
State EntryReader's momentary contract as a MUST, not a NoEscape SHOULD
dougqh Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ object KnownTagsEmitter {
"""
};

/**
* Each tag's id, indexed by serial; slot 0 (no tag) is 0. Lets a store that keeps only the
* 16-bit serial recover the full id, flag and slot bits included.
*/
static final long[] IDS_BY_SERIAL = {
0L,
""".trimIndent()
)
for (t in reg.tags.sortedBy { it.serial }) {
appendLine(" ${idC(t.ddName)},")
}
appendLine(
"""
};

/**
* The registry's name↔id tables, as a {@link KnownTagCodec.Resolver}. {@code KnownTagCodec}
* reads this field from its own holder, so the two classes complete each other: the codec owns
Expand All @@ -221,6 +236,11 @@ object KnownTagsEmitter {
int serial = KnownTagCodec.serialNum(tagId);
return serial < NAMES_BY_SERIAL.length ? NAMES_BY_SERIAL[serial] : null;
}

@Override
public long idOf(int serial) {
return IDS_BY_SERIAL[serial];
}

// openTelemetryNameOf: id -> OTel-namespace name on spans of a direction, null when
// the tag has none there. The caller (a serializer) owns any fall-back-to-Datadog-name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ class TagRegistryGeneratorPluginTest {
public final class KnownTagCodec {
public interface Resolver {
String nameOf(long id);
long idOf(int serial);
String openTelemetryNameOf(long id, int direction);
long keyOf(String name);
long directionalKeyOf(String name, int direction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class TypeConverterTest extends InstrumentationSpecification {
[:],
false,
"fakeType",
0,
trace,
null,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class TypeConverterTest extends InstrumentationSpecification {
[:],
false,
"fakeType",
0,
trace,
null,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class TypeConverterTest extends InstrumentationSpecification {
[:],
false,
"fakeType",
0,
trace,
null,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,11 @@ public final class TracerConfig {
public static final String TRACE_ORG_GUARD_STRICT = "trace.org.guard.strict";
public static final String TRACE_ORG_GUARD_TRUSTED_OPMS = "trace.org.guard.trusted.opms";

/**
* Stores known tags that have a dense-store slot in TagMap's dense store (no per-tag entry)
* instead of its hash buckets. Experimental, off by default.
*/
public static final String TRACE_DENSE_TAGS_ENABLED = "trace.experimental.dense.tags.enabled";

private TracerConfig() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ public void init(Blackhole blackhole) {
Collections.<String, String>emptyMap(),
false,
UTF8BytesString.create("type"),
0,
traceCollector,
null,
null,
Expand Down
116 changes: 116 additions & 0 deletions dd-trace-core/src/jmh/java/datadog/trace/core/GetTagBenchmark.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package datadog.trace.core;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

import datadog.trace.api.KnownTags;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;

/**
* Measures reading tags back from a live span, by how the tag is named: a known tag's name, a
* custom name, an OpenTelemetry name ({@code server.address}, which the core treats as a custom
* name), and misses. {@code getTag} takes the span's tag lock; {@code unsafeGetTag} reads without
* it, as the tracer's internal readers do.
*/
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(NANOSECONDS)
@Fork(value = 3)
public class GetTagBenchmark {
static final CoreTracer TRACER = CoreTracer.builder().build();

private DDSpan span;

/**
* The known tags the span holds, read in turn by the {@code *_cycle} arms so a read's cost is
* averaged over the span's tags rather than decided by whether one particular tag collides in its
* bucket. A power-of-two length lets the index wrap with a mask.
*/
private static final String[] KNOWN_HELD = {
"span.kind",
KnownTags.HTTP_ROUTE_NAME,
KnownTags.PEER_HOSTNAME_NAME,
KnownTags.HTTP_STATUS_CODE_NAME
};

private int next;

@Setup
public void setup() {
span = (DDSpan) TRACER.startSpan("benchmark", "get.tag");
span.setTag("span.kind", "client");
span.setTag(KnownTags.HTTP_ROUTE_NAME, "/users/{id}");
span.setTag(KnownTags.PEER_HOSTNAME_NAME, "db.example");
span.setTag(KnownTags.HTTP_STATUS_CODE_NAME, 200);
span.setTag("my.custom.tag", "custom");
span.setTag("my.other.tag", 42);
}

@TearDown
public void tearDown() {
span.finish();
}

@Benchmark
public Object knownTag_getTag() {
return span.getTag(KnownTags.HTTP_ROUTE_NAME);
}

@Benchmark
public Object customTag_getTag() {
return span.getTag("my.custom.tag");
}

@Benchmark
public Object aliasName_getTag() {
return span.getTag("server.address");
}

@Benchmark
public Object missingTag_getTag() {
return span.getTag("not.there");
}

/** A known tag the span doesn't hold: a clear slot bit can answer without a probe. */
@Benchmark
public Object missingKnownTag_getTag() {
return span.getTag(KnownTags.HTTP_METHOD_NAME);
}

@Benchmark
public Object missingKnownTag_unsafeGetTag() {
return span.unsafeGetTag(KnownTags.HTTP_METHOD_NAME);
}

@Benchmark
public Object knownTag_unsafeGetTag() {
return span.unsafeGetTag(KnownTags.HTTP_ROUTE_NAME);
}

/** Every known tag the span holds, in turn; see {@link #KNOWN_HELD}. */
@Benchmark
public Object knownTags_cycle_unsafeGetTag() {
return span.unsafeGetTag(KNOWN_HELD[next++ & (KNOWN_HELD.length - 1)]);
}

@Benchmark
public Object knownTags_cycle_getTag() {
return span.getTag(KNOWN_HELD[next++ & (KNOWN_HELD.length - 1)]);
}

@Benchmark
public Object customTag_unsafeGetTag() {
return span.unsafeGetTag("my.custom.tag");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ public void init(TraceCounters counters, Blackhole blackhole) {
Collections.<String, String>emptyMap(),
false,
"type",
0,
traceCollector,
null,
null,
Expand All @@ -80,7 +79,6 @@ public void init(TraceCounters counters, Blackhole blackhole) {
Collections.<String, String>emptyMap(),
false,
"type",
0,
traceCollector,
null,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ private DDSpan createSpanWithOrigin(int iter, final String origin) {
Collections.<String, String>emptyMap(),
false,
"type",
0,
traceCollector,
null,
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ public void setUp(Blackhole blackhole) {
Collections.<String, String>emptyMap(),
false,
"type",
0,
tracer.createTraceCollector(traceId),
null,
null,
Expand Down
66 changes: 56 additions & 10 deletions dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,43 @@ private static final class LocalRootSpanTags {
final TagMap tags;
final boolean needsIntercept;

/** The last {@link #traceLevelParent}, with the merged tracer tags it was built over. */
private volatile TraceLevelTags traceLevel;

LocalRootSpanTags(final TagMap tags, final boolean needsIntercept) {
this.tags = tags;
this.needsIntercept = needsIntercept;
}

/**
* All of a root span's trace-level tags in one frozen map -- these tags over {@code
* mergedTracerTags} -- for the root span to read through instead of copying them in. The tag
* registry colors trace-level tags separately, so they reuse span-level slot bits; keeping them
* out of the span's own store keeps its slot bits exact. Built once per config snapshot; a racy
* rebuild is harmless, since it builds the same map.
*/
TagMap traceLevelParent(final TagMap mergedTracerTags) {
TraceLevelTags cached = this.traceLevel;
if (cached != null && cached.mergedTracerTags == mergedTracerTags) {
return cached.parent;
}
TagMap parent = TagMap.create();
parent.putAll(mergedTracerTags);
parent.putAll(this.tags);
parent.freeze();
this.traceLevel = new TraceLevelTags(mergedTracerTags, parent);
return parent;
}
}

private static final class TraceLevelTags {
final TagMap mergedTracerTags;
final TagMap parent;

TraceLevelTags(final TagMap mergedTracerTags, final TagMap parent) {
this.mergedTracerTags = mergedTracerTags;
this.parent = parent;
}
}

private volatile LocalRootSpanTags localRootSpanTags;
Expand Down Expand Up @@ -2129,6 +2162,7 @@ protected static final DDSpanContext buildSpanContext(
final CharSequence origin;
final TagMap coreTags;
final boolean coreTagsNeedsIntercept;
final LocalRootSpanTags localRootSpanTags;
final TagMap rootSpanTags;
final boolean rootSpanTagsNeedsIntercept;
final DDSpanContext context;
Expand Down Expand Up @@ -2158,6 +2192,7 @@ protected static final DDSpanContext buildSpanContext(
origin = null;
coreTags = null;
coreTagsNeedsIntercept = false;
localRootSpanTags = null;
rootSpanTags = null;
rootSpanTagsNeedsIntercept = false;
parentServiceName = ddsc.getServiceName();
Expand Down Expand Up @@ -2232,7 +2267,7 @@ protected static final DDSpanContext buildSpanContext(
ciVisibilityContextData = null;
}

LocalRootSpanTags localRootSpanTags = tracer.localRootSpanTags;
localRootSpanTags = tracer.localRootSpanTags;
rootSpanTags = localRootSpanTags.tags;
rootSpanTagsNeedsIntercept = localRootSpanTags.needsIntercept;

Expand Down Expand Up @@ -2311,12 +2346,22 @@ protected static final DDSpanContext buildSpanContext(
final TagMap mergedTracerTags = traceConfig.mergedTracerTags;
boolean mergedTracerTagsNeedsIntercept = traceConfig.mergedTracerTagsNeedsIntercept;

final int tagsSize =
mergedTracerTags.size()
+ (null == tagLedger ? 0 : tagLedger.estimateSize())
+ (null == coreTags ? 0 : coreTags.size())
+ (null == rootSpanTags ? 0 : rootSpanTags.size())
+ (null == contextualTags ? 0 : contextualTags.size());
// With builder tags taking precedence, a root span reads its trace-level tags (root-span tags
// over the merged tracer tags) through one shared frozen parent instead of copying the
// root-span tags in. They become the precedence floor: the flag's order already puts them
// below builder and contextual tags, and now inbound header tags and prototype defaults also
// win over them. Tags needing interception are still copied in.
final boolean rootSpanTagsReadThrough =
localRootSpanTags != null
&& tracer.builderTagsPrecedence
&& !rootSpanTagsNeedsIntercept
&& !mergedTracerTagsNeedsIntercept;
final TagMap tagParent;
if (rootSpanTagsReadThrough) {
tagParent = localRootSpanTags.traceLevelParent(mergedTracerTags);
} else {
tagParent = mergedTracerTagsNeedsIntercept ? null : mergedTracerTags;
}

if (builderRequestContextDataAppSec != null) {
requestContextDataAppSec = builderRequestContextDataAppSec;
Expand Down Expand Up @@ -2345,7 +2390,6 @@ protected static final DDSpanContext buildSpanContext(
w3cBaggage,
errorFlag,
spanType,
tagsSize,
parentTraceCollector,
requestContextDataAppSec,
requestContextDataIast,
Expand All @@ -2356,7 +2400,7 @@ protected static final DDSpanContext buildSpanContext(
tracer.profilingContextIntegration,
tracer.injectBaggageAsTags,
tracer.injectLinksAsTags,
mergedTracerTagsNeedsIntercept ? null : mergedTracerTags);
tagParent);

// By setting the tags on the context we apply decorators to any tags that have been set via
// the builder. The `mergedTracerTags` are always applied first (the precedence floor:
Expand All @@ -2381,7 +2425,9 @@ protected static final DDSpanContext buildSpanContext(
}
if (tracer.builderTagsPrecedence) {
context.setAllTags(coreTags, coreTagsNeedsIntercept);
context.setAllTags(rootSpanTags, rootSpanTagsNeedsIntercept);
if (!rootSpanTagsReadThrough) {
context.setAllTags(rootSpanTags, rootSpanTagsNeedsIntercept);
}
context.setAllTags(contextualTags);
context.setAllTags(tagLedger);
} else {
Expand Down
Loading
Loading