Added support for Haystack trace propagation
MODIFY
dd-trace-api/src/main/java/datadog/trace/api/Config.java
dd-trace-api/src/main/java/datadog/trace/api/Config.java
@@ -137,7 +137,8 @@ public class Config {
public enum PropagationStyle {
DATADOG,
- B3
+ B3,
+ HAYSTACK
}
/** A tag intended for internal use only, hence not added to the public api DDTags class. */

ADD
dd-trace-ot/src/main/java/datadog/opentracing/propagation/HaystackHttpCodec.java
+package datadog.opentracing.propagation;
+
+import datadog.opentracing.DDSpanContext;
+import datadog.trace.api.sampling.PrioritySampling;
+import io.opentracing.SpanContext;
+import io.opentracing.propagation.TextMap;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static datadog.opentracing.propagation.HttpCodec.ZERO;
+import static datadog.opentracing.propagation.HttpCodec.validateUInt64BitsID;
+
+/**
+ * @author Alex Antonov
+ */
+@Slf4j
+public class HaystackHttpCodec {
+
+ private static final String OT_BAGGAGE_PREFIX = "Baggage-";
+ private static final String TRACE_ID_KEY = "Trace-ID";
+ private static final String SPAN_ID_KEY = "Span-ID";
+ private static final String PARENT_ID_KEY = "Parent_ID";
+
+ private HaystackHttpCodec() {
+ // This class should not be created. This also makes code coverage checks happy.
+ }
+
+ public static class Injector implements HttpCodec.Injector {
+
+ @Override
+ public void inject(final DDSpanContext context, final TextMap carrier) {
+ carrier.put(TRACE_ID_KEY, context.getTraceId());
+ carrier.put(SPAN_ID_KEY, context.getSpanId());
+ carrier.put(PARENT_ID_KEY, context.getParentId());
+
+ for (final Map.Entry<String, String> entry : context.baggageItems()) {
+ carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), HttpCodec.encode(entry.getValue()));
+ }
+ log.debug("{} - Haystack parent context injected", context.getTraceId());
+ }
+ }
+
+ public static class Extractor implements HttpCodec.Extractor {
+ private final Map<String, String> taggedHeaders;
+
+ public Extractor(final Map<String, String> taggedHeaders) {
+ this.taggedHeaders = new HashMap<>();
+ for (final Map.Entry<String, String> mapping : taggedHeaders.entrySet()) {
+ this.taggedHeaders.put(mapping.getKey().trim().toLowerCase(), mapping.getValue());
+ }
+ }
+
+ @Override
+ public SpanContext extract(final TextMap carrier) {
+ try {
+ Map<String, String> baggage = Collections.emptyMap();
+ Map<String, String> tags = Collections.emptyMap();
+ String traceId = ZERO;
+ String spanId = ZERO;
+ int samplingPriority = PrioritySampling.SAMPLER_KEEP;
+ String origin = null; // Always null
+
+ for (final Map.Entry<String, String> entry : carrier) {
+ final String key = entry.getKey().toLowerCase();
+ final String value = entry.getValue();
+
+ if (value == null) {
+ continue;
+ }
+
+ if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
+ traceId = validateUInt64BitsID(value, 10);
+ } else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
+ spanId = validateUInt64BitsID(value, 10);
+ } else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
+ if (baggage.isEmpty()) {
+ baggage = new HashMap<>();
+ }
+ baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), HttpCodec.decode(value));
+ }
+
+ if (taggedHeaders.containsKey(key)) {
+ if (tags.isEmpty()) {
+ tags = new HashMap<>();
+ }
+ tags.put(taggedHeaders.get(key), HttpCodec.decode(value));
+ }
+ }
+
+ if (!ZERO.equals(traceId)) {
+ final ExtractedContext context =
+ new ExtractedContext(traceId, spanId, samplingPriority, origin, baggage, tags);
+ context.lockSamplingPriority();
+
+ log.debug("{} - Parent context extracted", context.getTraceId());
+ return context;
+ } else if (origin != null || !tags.isEmpty()) {
+ log.debug("Tags context extracted");
+ return new TagContext(origin, tags);
+ }
+ } catch (final RuntimeException e) {
+ log.debug("Exception when extracting context", e);
+ }
+
+ return null;
+ }
+ }
+}

MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/propagation/HttpCodec.java
dd-trace-ot/src/main/java/datadog/opentracing/propagation/HttpCodec.java
@@ -41,6 +41,10 @@ public class HttpCodec {
injectors.add(new B3HttpCodec.Injector());
continue;
}
+ if (style == Config.PropagationStyle.HAYSTACK) {
+ injectors.add(new HaystackHttpCodec.Injector());
+ continue;
+ }
log.debug("No implementation found to inject propagation style: {}", style);
}
return new CompoundInjector(injectors);
@@ -58,6 +62,10 @@ public class HttpCodec {
extractors.add(new B3HttpCodec.Extractor(taggedHeaders));
continue;
}
+ if (style == Config.PropagationStyle.HAYSTACK) {
+ extractors.add(new HaystackHttpCodec.Extractor(taggedHeaders));
+ continue;
+ }
log.debug("No implementation found to extract propagation style: {}", style);
}
return new CompoundExtractor(extractors);

Added support for Haystack trace propagation