Merge pull request #317 from DataDog/tyler/tagged-headers
Add setting for collecting headers as tags during extraction
This commit is contained in:
commit
69ee39bfc2
|
@ -88,7 +88,8 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
Writer.Builder.forConfig(config),
|
Writer.Builder.forConfig(config),
|
||||||
Sampler.Builder.forConfig(config),
|
Sampler.Builder.forConfig(config),
|
||||||
DDTraceConfig.parseMap(config.getProperty(DDTraceConfig.SPAN_TAGS)),
|
DDTraceConfig.parseMap(config.getProperty(DDTraceConfig.SPAN_TAGS)),
|
||||||
DDTraceConfig.parseMap(config.getProperty(DDTraceConfig.SERVICE_MAPPING)));
|
DDTraceConfig.parseMap(config.getProperty(DDTraceConfig.SERVICE_MAPPING)),
|
||||||
|
DDTraceConfig.parseMap(config.getProperty(DDTraceConfig.HEADER_TAGS)));
|
||||||
log.debug("Using config: {}", config);
|
log.debug("Using config: {}", config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
writer,
|
writer,
|
||||||
sampler,
|
sampler,
|
||||||
Collections.<String, String>emptyMap(),
|
Collections.<String, String>emptyMap(),
|
||||||
|
Collections.<String, String>emptyMap(),
|
||||||
Collections.<String, String>emptyMap());
|
Collections.<String, String>emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +108,8 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
final Writer writer,
|
final Writer writer,
|
||||||
final Sampler sampler,
|
final Sampler sampler,
|
||||||
final Map<String, String> defaultSpanTags,
|
final Map<String, String> defaultSpanTags,
|
||||||
final Map<String, String> serviceNameMappings) {
|
final Map<String, String> serviceNameMappings,
|
||||||
|
final Map<String, String> taggedHeaders) {
|
||||||
this.serviceName = serviceName;
|
this.serviceName = serviceName;
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.writer.start();
|
this.writer.start();
|
||||||
|
@ -123,8 +126,8 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
});
|
});
|
||||||
|
|
||||||
registry = new CodecRegistry();
|
registry = new CodecRegistry();
|
||||||
registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec());
|
registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec(taggedHeaders));
|
||||||
registry.register(Format.Builtin.TEXT_MAP, new HTTPCodec());
|
registry.register(Format.Builtin.TEXT_MAP, new HTTPCodec(taggedHeaders));
|
||||||
if (this.writer instanceof DDAgentWriter && sampler instanceof DDApi.ResponseListener) {
|
if (this.writer instanceof DDAgentWriter && sampler instanceof DDApi.ResponseListener) {
|
||||||
final DDApi api = ((DDAgentWriter) this.writer).getApi();
|
final DDApi api = ((DDAgentWriter) this.writer).getApi();
|
||||||
api.addResponseListener((DDApi.ResponseListener) this.sampler);
|
api.addResponseListener((DDApi.ResponseListener) this.sampler);
|
||||||
|
@ -149,7 +152,8 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
writer,
|
writer,
|
||||||
new AllSampler(),
|
new AllSampler(),
|
||||||
DDTraceConfig.parseMap(new DDTraceConfig().getProperty(DDTraceConfig.SPAN_TAGS)),
|
DDTraceConfig.parseMap(new DDTraceConfig().getProperty(DDTraceConfig.SPAN_TAGS)),
|
||||||
DDTraceConfig.parseMap(new DDTraceConfig().getProperty(DDTraceConfig.SERVICE_MAPPING)));
|
DDTraceConfig.parseMap(new DDTraceConfig().getProperty(DDTraceConfig.SERVICE_MAPPING)),
|
||||||
|
DDTraceConfig.parseMap(new DDTraceConfig().getProperty(DDTraceConfig.HEADER_TAGS)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,6 +493,12 @@ public class DDTracer implements io.opentracing.Tracer {
|
||||||
traceId = ddsc.getTraceId();
|
traceId = ddsc.getTraceId();
|
||||||
parentSpanId = ddsc.getSpanId();
|
parentSpanId = ddsc.getSpanId();
|
||||||
baggage = ddsc.getBaggage();
|
baggage = ddsc.getBaggage();
|
||||||
|
if (this.tags.isEmpty() && !ddsc.getTags().isEmpty()) {
|
||||||
|
this.tags = new HashMap<>();
|
||||||
|
}
|
||||||
|
if (!ddsc.getTags().isEmpty()) {
|
||||||
|
tags.putAll(ddsc.getTags());
|
||||||
|
}
|
||||||
parentTrace = new PendingTrace(DDTracer.this, traceId);
|
parentTrace = new PendingTrace(DDTracer.this, traceId);
|
||||||
samplingPriority = ddsc.getSamplingPriority();
|
samplingPriority = ddsc.getSamplingPriority();
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,20 @@ public class ExtractedContext implements SpanContext {
|
||||||
private final Long spanId;
|
private final Long spanId;
|
||||||
private final int samplingPriority;
|
private final int samplingPriority;
|
||||||
private final Map<String, String> baggage;
|
private final Map<String, String> baggage;
|
||||||
|
private final Map<String, String> tags;
|
||||||
private final AtomicBoolean samplingPriorityLocked = new AtomicBoolean(false);
|
private final AtomicBoolean samplingPriorityLocked = new AtomicBoolean(false);
|
||||||
|
|
||||||
public ExtractedContext(
|
public ExtractedContext(
|
||||||
final Long traceId,
|
final Long traceId,
|
||||||
final Long spanId,
|
final Long spanId,
|
||||||
final int samplingPriority,
|
final int samplingPriority,
|
||||||
final Map<String, String> baggage) {
|
final Map<String, String> baggage,
|
||||||
|
final Map<String, String> tags) {
|
||||||
this.traceId = traceId;
|
this.traceId = traceId;
|
||||||
this.spanId = spanId;
|
this.spanId = spanId;
|
||||||
this.samplingPriority = samplingPriority;
|
this.samplingPriority = samplingPriority;
|
||||||
this.baggage = baggage;
|
this.baggage = baggage;
|
||||||
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,6 +50,10 @@ public class ExtractedContext implements SpanContext {
|
||||||
return baggage;
|
return baggage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getSamplingPriorityLocked() {
|
public boolean getSamplingPriorityLocked() {
|
||||||
return samplingPriorityLocked.get();
|
return samplingPriorityLocked.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,15 @@ public class HTTPCodec implements Codec<TextMap> {
|
||||||
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
|
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
|
||||||
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
|
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
|
||||||
|
|
||||||
|
private final Map<String, String> taggedHeaders;
|
||||||
|
|
||||||
|
public HTTPCodec(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
|
@Override
|
||||||
public void inject(final DDSpanContext context, final TextMap carrier) {
|
public void inject(final DDSpanContext context, final TextMap carrier) {
|
||||||
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
|
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
|
||||||
|
@ -38,6 +47,7 @@ public class HTTPCodec implements Codec<TextMap> {
|
||||||
public ExtractedContext extract(final TextMap carrier) {
|
public ExtractedContext extract(final TextMap carrier) {
|
||||||
|
|
||||||
Map<String, String> baggage = Collections.emptyMap();
|
Map<String, String> baggage = Collections.emptyMap();
|
||||||
|
Map<String, String> tags = Collections.emptyMap();
|
||||||
Long traceId = 0L;
|
Long traceId = 0L;
|
||||||
Long spanId = 0L;
|
Long spanId = 0L;
|
||||||
int samplingPriority = PrioritySampling.UNSET;
|
int samplingPriority = PrioritySampling.UNSET;
|
||||||
|
@ -56,10 +66,17 @@ public class HTTPCodec implements Codec<TextMap> {
|
||||||
} else if (key.equalsIgnoreCase(SAMPLING_PRIORITY_KEY)) {
|
} else if (key.equalsIgnoreCase(SAMPLING_PRIORITY_KEY)) {
|
||||||
samplingPriority = Integer.parseInt(entry.getValue());
|
samplingPriority = Integer.parseInt(entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (taggedHeaders.containsKey(key)) {
|
||||||
|
if (tags.isEmpty()) {
|
||||||
|
tags = new HashMap<>();
|
||||||
|
}
|
||||||
|
tags.put(taggedHeaders.get(key), decode(entry.getValue()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExtractedContext context = null;
|
ExtractedContext context = null;
|
||||||
if (traceId != 0L) {
|
if (traceId != 0L) {
|
||||||
context = new ExtractedContext(traceId, spanId, samplingPriority, baggage);
|
context = new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
|
||||||
context.lockSamplingPriority();
|
context.lockSamplingPriority();
|
||||||
|
|
||||||
log.debug("{} - Parent context extracted", context.getTraceId());
|
log.debug("{} - Parent context extracted", context.getTraceId());
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class DDTraceConfig extends Properties {
|
||||||
public static final String AGENT_PORT = "agent.port";
|
public static final String AGENT_PORT = "agent.port";
|
||||||
public static final String PRIORITY_SAMPLING = "priority.sampling";
|
public static final String PRIORITY_SAMPLING = "priority.sampling";
|
||||||
public static final String SPAN_TAGS = "trace.span.tags";
|
public static final String SPAN_TAGS = "trace.span.tags";
|
||||||
|
public static final String HEADER_TAGS = "trace.header.tags";
|
||||||
|
|
||||||
private final String serviceName = getPropOrEnv(PREFIX + SERVICE_NAME);
|
private final String serviceName = getPropOrEnv(PREFIX + SERVICE_NAME);
|
||||||
private final String serviceMapping = getPropOrEnv(PREFIX + SERVICE_MAPPING);
|
private final String serviceMapping = getPropOrEnv(PREFIX + SERVICE_MAPPING);
|
||||||
|
@ -38,6 +39,7 @@ public class DDTraceConfig extends Properties {
|
||||||
private final String agentPort = getPropOrEnv(PREFIX + AGENT_PORT);
|
private final String agentPort = getPropOrEnv(PREFIX + AGENT_PORT);
|
||||||
private final String prioritySampling = getPropOrEnv(PREFIX + PRIORITY_SAMPLING);
|
private final String prioritySampling = getPropOrEnv(PREFIX + PRIORITY_SAMPLING);
|
||||||
private final String spanTags = getPropOrEnv(PREFIX + SPAN_TAGS);
|
private final String spanTags = getPropOrEnv(PREFIX + SPAN_TAGS);
|
||||||
|
private final String headerTags = getPropOrEnv(PREFIX + HEADER_TAGS);
|
||||||
|
|
||||||
public DDTraceConfig() {
|
public DDTraceConfig() {
|
||||||
super();
|
super();
|
||||||
|
@ -56,6 +58,7 @@ public class DDTraceConfig extends Properties {
|
||||||
setIfNotNull(AGENT_PORT, agentPort);
|
setIfNotNull(AGENT_PORT, agentPort);
|
||||||
setIfNotNull(PRIORITY_SAMPLING, prioritySampling);
|
setIfNotNull(PRIORITY_SAMPLING, prioritySampling);
|
||||||
setIfNotNull(SPAN_TAGS, spanTags);
|
setIfNotNull(SPAN_TAGS, spanTags);
|
||||||
|
setIfNotNull(HEADER_TAGS, headerTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DDTraceConfig(final String serviceName) {
|
public DDTraceConfig(final String serviceName) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package datadog.opentracing
|
package datadog.opentracing
|
||||||
|
|
||||||
|
import datadog.opentracing.propagation.ExtractedContext
|
||||||
import datadog.trace.api.DDTags
|
import datadog.trace.api.DDTags
|
||||||
import datadog.trace.common.writer.ListWriter
|
import datadog.trace.common.writer.ListWriter
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
@ -222,6 +223,24 @@ class DDSpanBuilderTest extends Specification {
|
||||||
spans[(int) (Math.random() * nbSamples)].context.trace.containsAll(spans)
|
spans[(int) (Math.random() * nbSamples)].context.trace.containsAll(spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "ExtractedContext should populate new span details"() {
|
||||||
|
setup:
|
||||||
|
final DDSpan span = tracer.buildSpan("op name")
|
||||||
|
.asChildOf(extractedContext).start()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
span.traceId == extractedContext.traceId
|
||||||
|
span.parentId == extractedContext.spanId
|
||||||
|
span.samplingPriority == extractedContext.samplingPriority
|
||||||
|
span.context().baggageItems == extractedContext.baggage
|
||||||
|
span.context().@tags == extractedContext.tags
|
||||||
|
|
||||||
|
where:
|
||||||
|
extractedContext | _
|
||||||
|
new ExtractedContext(1, 2, 0, [:], [:]) | _
|
||||||
|
new ExtractedContext(3, 4, 1, ["asdf": "qwer"], ["zxcv": "1234"]) | _
|
||||||
|
}
|
||||||
|
|
||||||
def "global span tags populated on each span"() {
|
def "global span tags populated on each span"() {
|
||||||
setup:
|
setup:
|
||||||
System.setProperty("dd.trace.span.tags", tagString)
|
System.setProperty("dd.trace.span.tags", tagString)
|
||||||
|
|
|
@ -20,6 +20,8 @@ class HTTPCodecTest extends Specification {
|
||||||
@Shared
|
@Shared
|
||||||
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority"
|
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority"
|
||||||
|
|
||||||
|
HTTPCodec codec = new HTTPCodec(["SOME_HEADER": "some-tag"])
|
||||||
|
|
||||||
def "inject http headers"() {
|
def "inject http headers"() {
|
||||||
setup:
|
setup:
|
||||||
def writer = new ListWriter()
|
def writer = new ListWriter()
|
||||||
|
@ -47,7 +49,6 @@ class HTTPCodecTest extends Specification {
|
||||||
|
|
||||||
final Map<String, String> carrier = new HashMap<>()
|
final Map<String, String> carrier = new HashMap<>()
|
||||||
|
|
||||||
final HTTPCodec codec = new HTTPCodec()
|
|
||||||
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
|
@ -70,13 +71,13 @@ class HTTPCodecTest extends Specification {
|
||||||
(SPAN_ID_KEY.toUpperCase()) : "2",
|
(SPAN_ID_KEY.toUpperCase()) : "2",
|
||||||
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
|
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
|
||||||
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
|
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
|
||||||
|
SOME_HEADER : "my-interesting-info",
|
||||||
]
|
]
|
||||||
|
|
||||||
if (samplingPriority != PrioritySampling.UNSET) {
|
if (samplingPriority != PrioritySampling.UNSET) {
|
||||||
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
|
||||||
}
|
}
|
||||||
|
|
||||||
final HTTPCodec codec = new HTTPCodec()
|
|
||||||
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
|
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
|
@ -84,6 +85,7 @@ class HTTPCodecTest extends Specification {
|
||||||
context.getSpanId() == 2l
|
context.getSpanId() == 2l
|
||||||
context.getBaggage().get("k1") == "v1"
|
context.getBaggage().get("k1") == "v1"
|
||||||
context.getBaggage().get("k2") == "v2"
|
context.getBaggage().get("k2") == "v2"
|
||||||
|
context.getTags() == ["some-tag": "my-interesting-info"]
|
||||||
context.getSamplingPriority() == samplingPriority
|
context.getSamplingPriority() == samplingPriority
|
||||||
|
|
||||||
where:
|
where:
|
||||||
|
|
|
@ -14,6 +14,7 @@ import spock.lang.Specification
|
||||||
|
|
||||||
import static datadog.trace.common.DDTraceConfig.AGENT_HOST
|
import static datadog.trace.common.DDTraceConfig.AGENT_HOST
|
||||||
import static datadog.trace.common.DDTraceConfig.AGENT_PORT
|
import static datadog.trace.common.DDTraceConfig.AGENT_PORT
|
||||||
|
import static datadog.trace.common.DDTraceConfig.HEADER_TAGS
|
||||||
import static datadog.trace.common.DDTraceConfig.PREFIX
|
import static datadog.trace.common.DDTraceConfig.PREFIX
|
||||||
import static datadog.trace.common.DDTraceConfig.SERVICE_MAPPING
|
import static datadog.trace.common.DDTraceConfig.SERVICE_MAPPING
|
||||||
import static datadog.trace.common.DDTraceConfig.SERVICE_NAME
|
import static datadog.trace.common.DDTraceConfig.SERVICE_NAME
|
||||||
|
@ -114,16 +115,19 @@ class DDTraceConfigTest extends Specification {
|
||||||
setup:
|
setup:
|
||||||
System.setProperty(PREFIX + SERVICE_MAPPING, mapString)
|
System.setProperty(PREFIX + SERVICE_MAPPING, mapString)
|
||||||
System.setProperty(PREFIX + SPAN_TAGS, mapString)
|
System.setProperty(PREFIX + SPAN_TAGS, mapString)
|
||||||
|
System.setProperty(PREFIX + HEADER_TAGS, mapString)
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def tracer = new DDTracer()
|
def tracer = new DDTracer()
|
||||||
ServiceNameDecorator decorator = tracer.spanContextDecorators.values().flatten().find {
|
ServiceNameDecorator decorator = tracer.spanContextDecorators.values().flatten().find {
|
||||||
it instanceof ServiceNameDecorator
|
it instanceof ServiceNameDecorator
|
||||||
}
|
}
|
||||||
|
def taggedHeaders = tracer.registry.codecs.values().first().taggedHeaders
|
||||||
|
|
||||||
then:
|
then:
|
||||||
tracer.spanTags == map
|
tracer.spanTags == map
|
||||||
decorator.mappings == map
|
decorator.mappings == map
|
||||||
|
taggedHeaders == map
|
||||||
|
|
||||||
where:
|
where:
|
||||||
mapString | map
|
mapString | map
|
||||||
|
|
Loading…
Reference in New Issue