Remove codec for inject/extract

In preparation for OT 0.32 support.
This commit is contained in:
Tyler Benson 2019-02-05 14:49:07 -08:00
parent 7a430647a0
commit 326577d7df
7 changed files with 330 additions and 378 deletions

View File

@ -2,9 +2,8 @@ package datadog.opentracing;
import datadog.opentracing.decorators.AbstractDecorator; import datadog.opentracing.decorators.AbstractDecorator;
import datadog.opentracing.decorators.DDDecoratorsFactory; import datadog.opentracing.decorators.DDDecoratorsFactory;
import datadog.opentracing.propagation.Codec; import datadog.opentracing.propagation.DatadogHttpCodec;
import datadog.opentracing.propagation.ExtractedContext; import datadog.opentracing.propagation.ExtractedContext;
import datadog.opentracing.propagation.HTTPCodec;
import datadog.opentracing.propagation.TagContext; import datadog.opentracing.propagation.TagContext;
import datadog.opentracing.scopemanager.ContextualScopeManager; import datadog.opentracing.scopemanager.ContextualScopeManager;
import datadog.opentracing.scopemanager.ScopeContext; import datadog.opentracing.scopemanager.ScopeContext;
@ -24,6 +23,7 @@ import io.opentracing.ScopeManager;
import io.opentracing.Span; import io.opentracing.Span;
import io.opentracing.SpanContext; import io.opentracing.SpanContext;
import io.opentracing.propagation.Format; import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
import java.io.Closeable; import java.io.Closeable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -84,7 +84,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
return Integer.compare(o1.priority(), o2.priority()); return Integer.compare(o1.priority(), o2.priority());
} }
}); });
private final CodecRegistry registry;
private final DatadogHttpCodec.Injector injector;
private final DatadogHttpCodec.Extractor extractor;
private final AtomicInteger traceCount; private final AtomicInteger traceCount;
@ -238,9 +240,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
// The JVM is already shutting down. // The JVM is already shutting down.
} }
registry = new CodecRegistry(); injector = new DatadogHttpCodec.Injector();
registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec(taggedHeaders)); extractor = new DatadogHttpCodec.Extractor(taggedHeaders);
registry.register(Format.Builtin.TEXT_MAP, new HTTPCodec(taggedHeaders));
if (this.writer instanceof DDAgentWriter) { if (this.writer instanceof DDAgentWriter) {
final DDApi api = ((DDAgentWriter) this.writer).getApi(); final DDApi api = ((DDAgentWriter) this.writer).getApi();
traceCount = api.getTraceCounter(); traceCount = api.getTraceCounter();
@ -332,24 +334,21 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
@Override @Override
public <T> void inject(final SpanContext spanContext, final Format<T> format, final T carrier) { public <T> void inject(final SpanContext spanContext, final Format<T> format, final T carrier) {
if (!(carrier instanceof TextMap)) {
final Codec<T> codec = registry.get(format);
if (codec == null) {
log.debug("Unsupported format for propagation - {}", format.getClass().getName()); log.debug("Unsupported format for propagation - {}", format.getClass().getName());
} else { } else {
codec.inject((DDSpanContext) spanContext, carrier); injector.inject((DDSpanContext) spanContext, (TextMap) carrier);
} }
} }
@Override @Override
public <T> SpanContext extract(final Format<T> format, final T carrier) { public <T> SpanContext extract(final Format<T> format, final T carrier) {
final Codec<T> codec = registry.get(format); if (!(carrier instanceof TextMap)) {
if (codec == null) {
log.debug("Unsupported format for propagation - {}", format.getClass().getName()); log.debug("Unsupported format for propagation - {}", format.getClass().getName());
} else {
return codec.extract(carrier);
}
return null; return null;
} else {
return extractor.extract((TextMap) carrier);
}
} }
/** /**
@ -452,19 +451,6 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
return Config.get().getPartialFlushMinSpans(); return Config.get().getPartialFlushMinSpans();
} }
private static class CodecRegistry {
private final Map<Format<?>, Codec<?>> codecs = new HashMap<>();
<T> Codec<T> get(final Format<T> format) {
return (Codec<T>) codecs.get(format);
}
public <T> void register(final Format<T> format, final Codec<T> codec) {
codecs.put(format, codec);
}
}
/** Spans are built using this builder */ /** Spans are built using this builder */
public class DDSpanBuilder implements SpanBuilder { public class DDSpanBuilder implements SpanBuilder {
private final ScopeManager scopeManager; private final ScopeManager scopeManager;

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2016, Uber Technologies, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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> {
/**
* Serialize the span context using the provided carrier
*
* @param context
* @param carrier
*/
void inject(DDSpanContext context, T carrier);
/**
* Given a carrier, retrieve (rebuild) a span context. This context built will be use as the
* parent
*
* @param carrier
* @return the span context
*/
SpanContext extract(T carrier);
}

View File

@ -0,0 +1,150 @@
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;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/** A codec designed for HTTP transport via headers */
@Slf4j
public class DatadogHttpCodec {
// uint 64 bits max value, 2^64 - 1
static final BigInteger BIG_INTEGER_UINT64_MAX =
new BigInteger("2").pow(64).subtract(BigInteger.ONE);
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
public static class Injector {
public void inject(final DDSpanContext context, final TextMap carrier) {
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId()));
if (context.lockSamplingPriority()) {
carrier.put(SAMPLING_PRIORITY_KEY, String.valueOf(context.getSamplingPriority()));
}
for (final Map.Entry<String, String> entry : context.baggageItems()) {
carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue()));
}
log.debug("{} - Parent context injected", context.getTraceId());
}
private String encode(final String value) {
String encoded = value;
try {
encoded = URLEncoder.encode(value, "UTF-8");
} catch (final UnsupportedEncodingException e) {
log.info("Failed to encode value - {}", value);
}
return encoded;
}
}
public static class 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());
}
}
public SpanContext extract(final TextMap carrier) {
Map<String, String> baggage = Collections.emptyMap();
Map<String, String> tags = Collections.emptyMap();
String traceId = "0";
String spanId = "0";
int samplingPriority = PrioritySampling.UNSET;
for (final Map.Entry<String, String> entry : carrier) {
final String key = entry.getKey().toLowerCase();
final String val = entry.getValue();
if (val == null) {
continue;
}
if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
traceId = validateUInt64BitsID(val);
} else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
spanId = validateUInt64BitsID(val);
} else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
if (baggage.isEmpty()) {
baggage = new HashMap<>();
}
baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(val));
} else if (SAMPLING_PRIORITY_KEY.equalsIgnoreCase(key)) {
samplingPriority = Integer.parseInt(val);
}
if (taggedHeaders.containsKey(key)) {
if (tags.isEmpty()) {
tags = new HashMap<>();
}
tags.put(taggedHeaders.get(key), decode(val));
}
}
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;
}
private String decode(final String value) {
String decoded = value;
try {
decoded = URLDecoder.decode(value, "UTF-8");
} catch (final UnsupportedEncodingException e) {
log.info("Failed to decode value - {}", value);
}
return decoded;
}
/**
* Helper method to validate an ID String to verify that it is an unsigned 64 bits number and is
* within range.
*
* @param val the String that contains the ID
* @return the ID in String format if it passes validations
* @throws IllegalArgumentException if val is not a number or if the number is out of range
*/
private String validateUInt64BitsID(final String val) throws IllegalArgumentException {
try {
final BigInteger validate = new BigInteger(val);
if (validate.compareTo(BigInteger.ZERO) == -1
|| validate.compareTo(BIG_INTEGER_UINT64_MAX) == 1) {
throw new IllegalArgumentException(
"ID out of range, must be between 0 and 2^64-1, got: " + val);
}
return val;
} catch (final NumberFormatException nfe) {
throw new IllegalArgumentException(
"Expecting a number for trace ID or span ID, but got: " + val, nfe);
}
}
}
}

View File

@ -1,147 +0,0 @@
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;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/** A codec designed for HTTP transport via headers */
@Slf4j
public class HTTPCodec implements Codec<TextMap> {
// uint 64 bits max value, 2^64 - 1
static final BigInteger BIG_INTEGER_UINT64_MAX =
new BigInteger("2").pow(64).subtract(BigInteger.ONE);
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
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
public void inject(final DDSpanContext context, final TextMap carrier) {
carrier.put(TRACE_ID_KEY, String.valueOf(context.getTraceId()));
carrier.put(SPAN_ID_KEY, String.valueOf(context.getSpanId()));
if (context.lockSamplingPriority()) {
carrier.put(SAMPLING_PRIORITY_KEY, String.valueOf(context.getSamplingPriority()));
}
for (final Map.Entry<String, String> entry : context.baggageItems()) {
carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), encode(entry.getValue()));
}
log.debug("{} - Parent context injected", context.getTraceId());
}
@Override
public SpanContext extract(final TextMap carrier) {
Map<String, String> baggage = Collections.emptyMap();
Map<String, String> tags = Collections.emptyMap();
String traceId = "0";
String spanId = "0";
int samplingPriority = PrioritySampling.UNSET;
for (final Map.Entry<String, String> entry : carrier) {
final String key = entry.getKey().toLowerCase();
final String val = entry.getValue();
if (val == null) {
continue;
}
if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
traceId = validateUInt64BitsID(val);
} else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
spanId = validateUInt64BitsID(val);
} else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
if (baggage.isEmpty()) {
baggage = new HashMap<>();
}
baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(val));
} else if (SAMPLING_PRIORITY_KEY.equalsIgnoreCase(key)) {
samplingPriority = Integer.parseInt(val);
}
if (taggedHeaders.containsKey(key)) {
if (tags.isEmpty()) {
tags = new HashMap<>();
}
tags.put(taggedHeaders.get(key), decode(val));
}
}
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;
}
private String encode(final String value) {
String encoded = value;
try {
encoded = URLEncoder.encode(value, "UTF-8");
} catch (final UnsupportedEncodingException e) {
log.info("Failed to encode value - {}", value);
}
return encoded;
}
private String decode(final String value) {
String decoded = value;
try {
decoded = URLDecoder.decode(value, "UTF-8");
} catch (final UnsupportedEncodingException e) {
log.info("Failed to decode value - {}", value);
}
return decoded;
}
/**
* Helper method to validate an ID String to verify that it is an unsigned 64 bits number and is
* within range.
*
* @param val the String that contains the ID
* @return the ID in String format if it passes validations
* @throws IllegalArgumentException if val is not a number or if the number is out of range
*/
private String validateUInt64BitsID(final String val) throws IllegalArgumentException {
try {
final BigInteger validate = new BigInteger(val);
if (validate.compareTo(BigInteger.ZERO) == -1
|| validate.compareTo(BIG_INTEGER_UINT64_MAX) == 1) {
throw new IllegalArgumentException(
"ID out of range, must be between 0 and 2^64-1, got: " + val);
}
return val;
} catch (final NumberFormatException nfe) {
throw new IllegalArgumentException(
"Expecting a number for trace ID or span ID, but got: " + val, nfe);
}
}
}

View File

@ -1,160 +1,18 @@
package datadog.opentracing.propagation package datadog.opentracing.propagation
import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import io.opentracing.propagation.TextMapExtractAdapter import io.opentracing.propagation.TextMapExtractAdapter
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Shared
import spock.lang.Specification import spock.lang.Specification
import static datadog.opentracing.propagation.HTTPCodec.BIG_INTEGER_UINT64_MAX import static datadog.opentracing.propagation.DatadogHttpCodec.BIG_INTEGER_UINT64_MAX
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
import static datadog.opentracing.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
class HTTPCodecTest extends Specification { class DatadogHttpExtractorTest extends Specification {
@Shared
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"
@Shared
private static final String TRACE_ID_KEY = "x-datadog-trace-id"
@Shared
private static final String SPAN_ID_KEY = "x-datadog-parent-id"
@Shared
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority"
HTTPCodec codec = new HTTPCodec(["SOME_HEADER": "some-tag"]) DatadogHttpCodec.Extractor extractor = new DatadogHttpCodec.Extractor(["SOME_HEADER": "some-tag"])
def "inject http headers"() {
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
"1",
"2",
"0",
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, "1", [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == "1"
carrier.get(SPAN_ID_KEY) == "2"
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "inject http headers with larger than Java long IDs"() {
String largeTraceId = "9523372036854775807"
String largeSpanId = "15815582334751494918"
String largeParentId = "15815582334751494914"
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
largeTraceId,
largeSpanId,
largeParentId,
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, largeTraceId, [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == largeTraceId
carrier.get(SPAN_ID_KEY) == largeSpanId
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "inject http headers with uint 64 max IDs"() {
String largeTraceId = "18446744073709551615"
String largeSpanId = "18446744073709551614"
String largeParentId = "18446744073709551613"
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
largeTraceId,
largeSpanId,
largeParentId,
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, largeTraceId, [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
codec.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == largeTraceId
carrier.get(SPAN_ID_KEY) == largeSpanId
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "extract http headers"() { def "extract http headers"() {
setup: setup:
@ -170,7 +28,7 @@ class HTTPCodecTest extends Specification {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority)) actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
} }
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual)) final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
expect: expect:
context.getTraceId() == "1" context.getTraceId() == "1"
@ -192,7 +50,7 @@ class HTTPCodecTest extends Specification {
SOME_HEADER: "my-interesting-info", SOME_HEADER: "my-interesting-info",
] ]
TagContext context = codec.extract(new TextMapExtractAdapter(actual)) TagContext context = extractor.extract(new TextMapExtractAdapter(actual))
expect: expect:
!(context instanceof ExtractedContext) !(context instanceof ExtractedContext)
@ -201,7 +59,7 @@ class HTTPCodecTest extends Specification {
def "extract empty headers returns null"() { def "extract empty headers returns null"() {
expect: expect:
codec.extract(new TextMapExtractAdapter(["ignored-header": "ignored-value"])) == null extractor.extract(new TextMapExtractAdapter(["ignored-header": "ignored-value"])) == null
} }
def "extract http headers with larger than Java long IDs"() { def "extract http headers with larger than Java long IDs"() {
@ -220,7 +78,7 @@ class HTTPCodecTest extends Specification {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority)) actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
} }
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual)) final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
expect: expect:
context.getTraceId() == largeTraceId context.getTraceId() == largeTraceId
@ -251,7 +109,7 @@ class HTTPCodecTest extends Specification {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority)) actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
} }
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual)) final ExtractedContext context = extractor.extract(new TextMapExtractAdapter(actual))
expect: expect:
context.getTraceId() == BIG_INTEGER_UINT64_MAX.toString() context.getTraceId() == BIG_INTEGER_UINT64_MAX.toString()
@ -282,7 +140,7 @@ class HTTPCodecTest extends Specification {
} }
when: when:
codec.extract(new TextMapExtractAdapter(actual)) extractor.extract(new TextMapExtractAdapter(actual))
then: then:
def iae = thrown(IllegalArgumentException) def iae = thrown(IllegalArgumentException)
@ -310,7 +168,7 @@ class HTTPCodecTest extends Specification {
} }
when: when:
codec.extract(new TextMapExtractAdapter(actual)) extractor.extract(new TextMapExtractAdapter(actual))
then: then:
thrown(IllegalArgumentException) thrown(IllegalArgumentException)
@ -336,7 +194,7 @@ class HTTPCodecTest extends Specification {
} }
when: when:
codec.extract(new TextMapExtractAdapter(actual)) extractor.extract(new TextMapExtractAdapter(actual))
then: then:
thrown(IllegalArgumentException) thrown(IllegalArgumentException)

View File

@ -0,0 +1,151 @@
package datadog.opentracing.propagation
import datadog.opentracing.DDSpanContext
import datadog.opentracing.DDTracer
import datadog.opentracing.PendingTrace
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.writer.ListWriter
import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Specification
import static datadog.opentracing.propagation.DatadogHttpCodec.OT_BAGGAGE_PREFIX
import static datadog.opentracing.propagation.DatadogHttpCodec.SAMPLING_PRIORITY_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.SPAN_ID_KEY
import static datadog.opentracing.propagation.DatadogHttpCodec.TRACE_ID_KEY
class DatadogHttpInjectorTest extends Specification {
DatadogHttpCodec.Injector injector = new DatadogHttpCodec.Injector()
def "inject http headers"() {
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
"1",
"2",
"0",
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, "1", [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == "1"
carrier.get(SPAN_ID_KEY) == "2"
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "inject http headers with larger than Java long IDs"() {
String largeTraceId = "9523372036854775807"
String largeSpanId = "15815582334751494918"
String largeParentId = "15815582334751494914"
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
largeTraceId,
largeSpanId,
largeParentId,
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, largeTraceId, [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == largeTraceId
carrier.get(SPAN_ID_KEY) == largeSpanId
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "inject http headers with uint 64 max IDs"() {
String largeTraceId = "18446744073709551615"
String largeSpanId = "18446744073709551614"
String largeParentId = "18446744073709551613"
setup:
def writer = new ListWriter()
def tracer = new DDTracer(writer)
final DDSpanContext mockedContext =
new DDSpanContext(
largeTraceId,
largeSpanId,
largeParentId,
"fakeService",
"fakeOperation",
"fakeResource",
samplingPriority,
new HashMap<String, String>() {
{
put("k1", "v1")
put("k2", "v2")
}
},
false,
"fakeType",
null,
new PendingTrace(tracer, largeTraceId, [:]),
tracer)
final Map<String, String> carrier = new HashMap<>()
injector.inject(mockedContext, new TextMapInjectAdapter(carrier))
expect:
carrier.get(TRACE_ID_KEY) == largeTraceId
carrier.get(SPAN_ID_KEY) == largeSpanId
carrier.get(SAMPLING_PRIORITY_KEY) == (samplingPriority == PrioritySampling.UNSET ? null : String.valueOf(samplingPriority))
carrier.get(OT_BAGGAGE_PREFIX + "k1") == "v1"
carrier.get(OT_BAGGAGE_PREFIX + "k2") == "v2"
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
}

View File

@ -78,7 +78,7 @@ class DDTracerTest extends Specification {
when: when:
def config = new Config() def config = new Config()
def tracer = new DDTracer(config) def tracer = new DDTracer(config)
def taggedHeaders = tracer.registry.codecs.values().first().taggedHeaders def taggedHeaders = tracer.extractor.taggedHeaders
then: then:
tracer.defaultSpanTags == map tracer.defaultSpanTags == map