diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index f01d250f8bc..f1b12ffe40d 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -49,7 +49,6 @@ import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Function; import javax.annotation.Nonnull; import org.slf4j.Logger; @@ -165,16 +164,10 @@ public class DDSpanContext implements AgentSpanContext, ProfilerContext { private volatile boolean topLevel; /** - * This span's own propagation tags, when they differ from the trace's. Only a non-root span that - * is the target of a write (e.g. {@code _dd.p.ts}) gets one. Access via {@link - * #ownPropagationTags()}. + * This span's own propagation tags, when it was constructed with some while its trace already had + * propagation tags. Otherwise null, and the trace's are used. */ - private volatile PropagationTags propagationTags; - - private static final AtomicReferenceFieldUpdater - PROPAGATION_TAGS = - AtomicReferenceFieldUpdater.newUpdater( - DDSpanContext.class, PropagationTags.class, "propagationTags"); + private final PropagationTags propagationTags; private volatile PathwayContext pathwayContext; @@ -367,10 +360,13 @@ public DDSpanContext( if (propagationTags != null) { propagationTags.updateTraceIdHighOrderBits(this.traceId.toHighOrderLong()); - if (traceCollector.initPropagationTags(propagationTags) != propagationTags) { - // the trace already has propagation tags, so these are this span's own - this.propagationTags = propagationTags; - } + // if the trace already has propagation tags, these are this span's own + this.propagationTags = + traceCollector.initPropagationTags(propagationTags) != propagationTags + ? propagationTags + : null; + } else { + this.propagationTags = null; } if (origin != null) { setOrigin(origin); @@ -389,19 +385,6 @@ private PropagationTags tracePropagationTags() { return tags != null ? tags : traceCollector.initPropagationTags(newEmptyPropagationTags()); } - /** - * Returns this span's own propagation tags: the trace's for the local root, otherwise an instance - * created on first use. - */ - private PropagationTags ownPropagationTags() { - PropagationTags tags = ownPropagationTagsIfPresent(); - if (tags != null) { - return tags; - } - PropagationTags created = newEmptyPropagationTags(); - return PROPAGATION_TAGS.compareAndSet(this, null, created) ? created : propagationTags; - } - /** This span's own propagation tags, or null if a non-root span has none yet. */ private PropagationTags ownPropagationTagsIfPresent() { PropagationTags tags = propagationTags; @@ -659,11 +642,13 @@ public void forceKeep(byte samplingMechanism) { } public void addPropagatedTraceSource(final int value) { - ownPropagationTags().addTraceSource(value); + // trace level, so it's propagated whichever span it's set on + tracePropagationTags().addTraceSource(value); } public void updateDebugPropagation(String value) { - ownPropagationTags().updateDebugPropagation(value); + // trace level, so it's propagated whichever span it's set on + tracePropagationTags().updateDebugPropagation(value); } /** diff --git a/dd-trace-core/src/test/java/datadog/trace/core/ChildSpanPropagationTagsTest.java b/dd-trace-core/src/test/java/datadog/trace/core/ChildSpanPropagationTagsTest.java index 6d2b3339ffa..6c95a5c50f2 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/ChildSpanPropagationTagsTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/ChildSpanPropagationTagsTest.java @@ -93,27 +93,37 @@ void rootSerializationUnaffectedByChildren() { } @Test - void traceSourceOnChildStaysOnChild() { + void traceSourceOnChildIsTraceLevel() { DDSpan root = (DDSpan) tracer.buildSpan("test", "root").start(); DDSpan child = childOf(root); child.setTag("_dd.p.ts", ProductTraceSource.ASM); - assertTrue(child.spanContext().hasOwnPropagationTags()); - assertEquals("02", ownTags(child).get("_dd.p.ts")); - assertFalse(root.spanContext().getPropagationTags().createTagMap().containsKey("_dd.p.ts")); + assertTraceLevel(root, child, "_dd.p.ts", "02"); } @Test - void debugPropagationOnChildStaysOnChild() { + void debugPropagationOnChildIsTraceLevel() { DDSpan root = (DDSpan) tracer.buildSpan("test", "root").start(); DDSpan child = childOf(root); child.setTag("_dd.p.debug", "probe"); - assertTrue(child.spanContext().hasOwnPropagationTags()); - assertEquals("probe", ownTags(child).get("_dd.p.debug")); - assertFalse(root.spanContext().getPropagationTags().createTagMap().containsKey("_dd.p.debug")); + assertTraceLevel(root, child, "_dd.p.debug", "probe"); + } + + /** A tag set on a child lands on the trace: injected, and serialized with the local root. */ + private void assertTraceLevel(DDSpan root, DDSpan child, String tag, String value) { + assertFalse(child.spanContext().hasOwnPropagationTags()); + PropagationTags trace = root.spanContext().getPropagationTags(); + assertSame(trace, child.spanContext().getPropagationTags()); + assertEquals(value, trace.createTagMap().get(tag)); + assertTrue( + trace.headerValue(PropagationTags.HeaderType.DATADOG).contains(tag + "=" + value), + trace.headerValue(PropagationTags.HeaderType.DATADOG)); + assertEquals(value, tags(root, ROOT_PROPAGATION_TAGS).get(tag)); + assertEquals(value, ownTags(root).get(tag)); + assertEquals(expectedOwnTags(child), ownTags(child)); } private DDSpan extractedRoot(DDTraceId traceId, String header) {