Fix issue with saving tags when not propagating trace.
Previously, when setting headers as tags, the tags would only be saved if the request was propagated from another trace.
MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java
dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java
@@ -5,6 +5,7 @@ import datadog.opentracing.decorators.DDDecoratorsFactory;
import datadog.opentracing.propagation.Codec;
import datadog.opentracing.propagation.ExtractedContext;
import datadog.opentracing.propagation.HTTPCodec;
+import datadog.opentracing.propagation.TagContext;
import datadog.opentracing.scopemanager.ContextualScopeManager;
import datadog.opentracing.scopemanager.ScopeContext;
import datadog.trace.api.Config;
@@ -545,25 +546,36 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
spanType = ddsc.getSpanType();
}
+ } else {
+ if (parentContext instanceof ExtractedContext) {
// Propagate external trace
- } else if (parentContext instanceof ExtractedContext) {
- final ExtractedContext ddsc = (ExtractedContext) parentContext;
- traceId = ddsc.getTraceId();
- parentSpanId = ddsc.getSpanId();
- baggage = ddsc.getBaggage();
- tags.putAll(ddsc.getTags());
- tags.put(Config.RUNTIME_ID_TAG, runtimeId);
- parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings);
- samplingPriority = ddsc.getSamplingPriority();
-
- // Start a new trace
+ final ExtractedContext extractedContext = (ExtractedContext) parentContext;
+ traceId = extractedContext.getTraceId();
+ parentSpanId = extractedContext.getSpanId();
+ samplingPriority = extractedContext.getSamplingPriority();
+ baggage = extractedContext.getBaggage();
} else {
+ // Start a new trace
traceId = generateNewId();
parentSpanId = "0";
+ samplingPriority = PrioritySampling.UNSET;
baggage = null;
+ }
+
+ // Get header tags whether propagating or not.
+ if (parentContext instanceof TagContext) {
+ final TagContext tagContext = (TagContext) parentContext;
+
+ if (tags.isEmpty() && !tagContext.getTags().isEmpty()) {
+ tags = new HashMap<>();
+ }
+ if (!tagContext.getTags().isEmpty()) {
+ tags.putAll(tagContext.getTags());
+ }
+ }
tags.put(Config.RUNTIME_ID_TAG, runtimeId);
+
parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings);
- samplingPriority = PrioritySampling.UNSET;
}
if (serviceName == null) {

MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/propagation/Codec.java
dd-trace-ot/src/main/java/datadog/opentracing/propagation/Codec.java
package datadog.opentracing.propagation;
import datadog.opentracing.DDSpanContext;
+import io.opentracing.SpanContext;
/** A codec is a simple object that can encode and decode a span context through a carrier */
public interface Codec<T> {
@@ -41,5 +42,5 @@ public interface Codec<T> {
* @param carrier
* @return the span context
*/
- ExtractedContext extract(T carrier);
+ SpanContext extract(T carrier);
}

MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/propagation/ExtractedContext.java
dd-trace-ot/src/main/java/datadog/opentracing/propagation/ExtractedContext.java
package datadog.opentracing.propagation;
-import io.opentracing.SpanContext;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
-public class ExtractedContext implements SpanContext {
+public class ExtractedContext extends TagContext {
private final String traceId;
private final String spanId;
private final int samplingPriority;
private final Map<String, String> baggage;
- private final Map<String, String> tags;
private final AtomicBoolean samplingPriorityLocked = new AtomicBoolean(false);
public ExtractedContext(
@@ -18,11 +16,11 @@ public class ExtractedContext implements SpanContext {
final int samplingPriority,
final Map<String, String> baggage,
final Map<String, String> tags) {
+ super(tags);
this.traceId = traceId;
this.spanId = spanId;
this.samplingPriority = samplingPriority;
this.baggage = baggage;
- this.tags = tags;
}
@Override
@@ -50,10 +48,6 @@ public class ExtractedContext implements SpanContext {
return baggage;
}
- public Map<String, String> getTags() {
- return tags;
- }
-
public boolean getSamplingPriorityLocked() {
return samplingPriorityLocked.get();
}

MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/propagation/HTTPCodec.java
dd-trace-ot/src/main/java/datadog/opentracing/propagation/HTTPCodec.java
@@ -2,6 +2,7 @@ package datadog.opentracing.propagation;
import datadog.opentracing.DDSpanContext;
import datadog.trace.api.sampling.PrioritySampling;
+import io.opentracing.SpanContext;
import io.opentracing.propagation.TextMap;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
@@ -49,7 +50,7 @@ public class HTTPCodec implements Codec<TextMap> {
}
@Override
- public ExtractedContext extract(final TextMap carrier) {
+ public SpanContext extract(final TextMap carrier) {
Map<String, String> baggage = Collections.emptyMap();
Map<String, String> tags = Collections.emptyMap();
@@ -81,12 +82,17 @@ public class HTTPCodec implements Codec<TextMap> {
tags.put(taggedHeaders.get(key), decode(val));
}
}
- ExtractedContext context = null;
- if (!"0".equals(traceId)) {
- context = new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
- context.lockSamplingPriority();
- log.debug("{} - Parent context extracted", context.getTraceId());
+ SpanContext context = null;
+ if (!"0".equals(traceId)) {
+ final ExtractedContext ctx =
+ new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
+ ctx.lockSamplingPriority();
+
+ log.debug("{} - Parent context extracted", ctx.getTraceId());
+ context = ctx;
+ } else if (!tags.isEmpty()) {
+ context = new TagContext(tags);
}
return context;

ADD
dd-trace-ot/src/main/java/datadog/opentracing/propagation/TagContext.java
+package datadog.opentracing.propagation;
+
+import io.opentracing.SpanContext;
+import java.util.Collections;
+import java.util.Map;
+
+public class TagContext implements SpanContext {
+ private final Map<String, String> tags;
+
+ public TagContext(final Map<String, String> tags) {
+ this.tags = tags;
+ }
+
+ public Map<String, String> getTags() {
+ return tags;
+ }
+
+ @Override
+ public Iterable<Map.Entry<String, String>> baggageItems() {
+ return Collections.emptyList();
+ }
+}

MODIFY
dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HTTPCodecTest.groovy
dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HTTPCodecTest.groovy
@@ -186,6 +186,24 @@ class HTTPCodecTest extends Specification {
PrioritySampling.SAMPLER_KEEP | _
}
+ def "extract header tags with no propagation"() {
+ setup:
+ final Map<String, String> actual = [
+ SOME_HEADER: "my-interesting-info",
+ ]
+
+ TagContext context = codec.extract(new TextMapExtractAdapter(actual))
+
+ expect:
+ !(context instanceof ExtractedContext)
+ context.getTags() == ["some-tag": "my-interesting-info"]
+ }
+
+ def "extract empty headers returns null"() {
+ expect:
+ codec.extract(new TextMapExtractAdapter(["ignored-header": "ignored-value"])) == null
+ }
+
def "extract http headers with larger than Java long IDs"() {
setup:
String largeTraceId = "9523372036854775807"

Fix issue with saving tags when not propagating trace.

Previously, when setting headers as tags, the tags would only be saved if the request was propagated from another trace.