Added support for Haystack trace propagation

This commit is contained in:
Alex Antonov 2019-06-20 17:28:02 -05:00
parent 79c519e4fe
commit 93ae2678ff
3 changed files with 121 additions and 1 deletions

View File

@ -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. */

View File

@ -0,0 +1,111 @@
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;
}
}
}

View File

@ -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);