Merge pull request #392 from DataDog/gary/uint64-id-support

Change the internal storage and handling of trace ID, span ID, and pa…
This commit is contained in:
Gary Huang 2018-07-30 15:01:10 -04:00 committed by GitHub
commit 4c88e1a0a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 446 additions and 132 deletions

View File

@ -47,8 +47,8 @@ class AkkaHttpServerInstrumentationTest extends AgentTestRunner {
assertTraces(TEST_WRITER, 1) { assertTraces(TEST_WRITER, 1) {
trace(0, 2) { trace(0, 2) {
span(0) { span(0) {
traceId 123 traceId "123"
parentId 456 parentId "456"
serviceName "unnamed-java-app" serviceName "unnamed-java-app"
operationName "akka-http.request" operationName "akka-http.request"
resourceName "GET /test" resourceName "GET /test"

View File

@ -87,7 +87,7 @@ class AWSClientTest extends AgentTestRunner {
span1.resourceName == "apache.http" span1.resourceName == "apache.http"
span1.type == null span1.type == null
!span1.context().getErrorFlag() !span1.context().getErrorFlag()
span1.context().parentId == 0 span1.context().parentId == "0"
def tags1 = span1.context().tags def tags1 = span1.context().tags
@ -130,7 +130,7 @@ class AWSClientTest extends AgentTestRunner {
span.resourceName == "$service.$operation" span.resourceName == "$service.$operation"
span.type == "web" span.type == "web"
!span.context().getErrorFlag() !span.context().getErrorFlag()
span.context().parentId == 0 span.context().parentId == "0"
def tags = span.context().tags def tags = span.context().tags
tags[Tags.COMPONENT.key] == "java-aws-sdk" tags[Tags.COMPONENT.key] == "java-aws-sdk"

View File

@ -116,7 +116,7 @@ class AWSClientTest extends AgentTestRunner {
span1.resourceName == "apache.http" span1.resourceName == "apache.http"
span1.type == null span1.type == null
!span1.context().getErrorFlag() !span1.context().getErrorFlag()
span1.context().parentId == 0 span1.context().parentId == "0"
def tags1 = span1.context().tags def tags1 = span1.context().tags
@ -159,7 +159,7 @@ class AWSClientTest extends AgentTestRunner {
span.resourceName == "$service.$operation" span.resourceName == "$service.$operation"
span.type == "web" span.type == "web"
!span.context().getErrorFlag() !span.context().getErrorFlag()
span.context().parentId == 0 span.context().parentId == "0"
def tags = span.context().tags def tags = span.context().tags
tags[Tags.COMPONENT.key] == "java-aws-sdk" tags[Tags.COMPONENT.key] == "java-aws-sdk"

View File

@ -57,7 +57,7 @@ class JaxRsClientTest extends AgentTestRunner {
span.resourceName == "GET /ping" span.resourceName == "GET /ping"
span.type == "http" span.type == "http"
!span.context().getErrorFlag() !span.context().getErrorFlag()
span.context().parentId == 0 span.context().parentId == "0"
def tags = span.context().tags def tags = span.context().tags

View File

@ -66,7 +66,7 @@ class JettyHandlerTest extends AgentTestRunner {
context.resourceName == "GET ${handler.class.name}" context.resourceName == "GET ${handler.class.name}"
context.spanType == DDSpanTypes.WEB_SERVLET context.spanType == DDSpanTypes.WEB_SERVLET
!context.getErrorFlag() !context.getErrorFlag()
context.parentId == 0 context.parentId == "0"
def tags = context.tags def tags = context.tags
tags["http.url"] == "http://localhost:$port/" tags["http.url"] == "http://localhost:$port/"
tags["http.method"] == "GET" tags["http.method"] == "GET"
@ -154,7 +154,7 @@ class JettyHandlerTest extends AgentTestRunner {
context.resourceName == "GET ${handler.class.name}" context.resourceName == "GET ${handler.class.name}"
context.spanType == DDSpanTypes.WEB_SERVLET context.spanType == DDSpanTypes.WEB_SERVLET
context.getErrorFlag() context.getErrorFlag()
context.parentId == 0 context.parentId == "0"
def tags = context.tags def tags = context.tags
tags["http.url"] == "http://localhost:$port/" tags["http.url"] == "http://localhost:$port/"
tags["http.method"] == "GET" tags["http.method"] == "GET"

View File

@ -85,7 +85,7 @@ class KafkaClientTest extends AgentTestRunner {
t1span1.resourceName == "Produce Topic $SHARED_TOPIC" t1span1.resourceName == "Produce Topic $SHARED_TOPIC"
t1span1.type == "queue" t1span1.type == "queue"
!t1span1.context().getErrorFlag() !t1span1.context().getErrorFlag()
t1span1.context().parentId == 0 t1span1.context().parentId == "0"
def t1tags1 = t1span1.context().tags def t1tags1 = t1span1.context().tags
t1tags1["component"] == "java-kafka" t1tags1["component"] == "java-kafka"

View File

@ -111,7 +111,7 @@ class KafkaStreamsTest extends AgentTestRunner {
t1span1.resourceName == "Produce Topic $STREAM_PENDING" t1span1.resourceName == "Produce Topic $STREAM_PENDING"
t1span1.type == "queue" t1span1.type == "queue"
!t1span1.context().getErrorFlag() !t1span1.context().getErrorFlag()
t1span1.context().parentId == 0 t1span1.context().parentId == "0"
def t1tags1 = t1span1.context().tags def t1tags1 = t1span1.context().tags
t1tags1["component"] == "java-kafka" t1tags1["component"] == "java-kafka"

View File

@ -45,7 +45,7 @@ class OkHttp3Test extends AgentTestRunner {
span1.resourceName == "okhttp.http" span1.resourceName == "okhttp.http"
span1.type == DDSpanTypes.WEB_SERVLET span1.type == DDSpanTypes.WEB_SERVLET
!span1.context().getErrorFlag() !span1.context().getErrorFlag()
span1.context().parentId == 0 span1.context().parentId == "0"
def tags1 = span1.context().tags def tags1 = span1.context().tags

View File

@ -45,8 +45,8 @@ class Play26Test extends AgentTestRunner {
assertTraces(TEST_WRITER, 1) { assertTraces(TEST_WRITER, 1) {
trace(0, 3) { trace(0, 3) {
span(0) { span(0) {
traceId 123 traceId "123"
parentId 456 parentId "456"
serviceName "unnamed-java-app" serviceName "unnamed-java-app"
operationName "akka-http.request" operationName "akka-http.request"
resourceName "GET /helloplay/:from" resourceName "GET /helloplay/:from"

View File

@ -46,8 +46,8 @@ class Play24Test extends AgentTestRunner {
playTrace.size() == 2 playTrace.size() == 2
playTrace[1].operationName == 'TracedWork$.doWork' playTrace[1].operationName == 'TracedWork$.doWork'
root.traceId == 123 root.traceId == "123"
root.parentId == 456 root.parentId == "456"
root.serviceName == "unnamed-java-app" root.serviceName == "unnamed-java-app"
root.operationName == "play.request" root.operationName == "play.request"
root.resourceName == "GET /helloplay/:from" root.resourceName == "GET /helloplay/:from"

View File

@ -81,7 +81,7 @@ class SparkJavaBasedTest extends AgentTestRunner {
context.resourceName == "GET /param/:param" context.resourceName == "GET /param/:param"
context.spanType == DDSpanTypes.WEB_SERVLET context.spanType == DDSpanTypes.WEB_SERVLET
!context.getErrorFlag() !context.getErrorFlag()
context.parentId == 0 context.parentId == "0"
def tags = context.tags def tags = context.tags
tags["http.url"] == "http://localhost:$port/param/asdf1234" tags["http.url"] == "http://localhost:$port/param/asdf1234"
tags["http.method"] == "GET" tags["http.method"] == "GET"

View File

@ -43,7 +43,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span.context().resourceName == "GET /param/{parameter}/" span.context().resourceName == "GET /param/{parameter}/"
span.context().spanType == DDSpanTypes.WEB_SERVLET span.context().spanType == DDSpanTypes.WEB_SERVLET
!span.context().getErrorFlag() !span.context().getErrorFlag()
span.context().parentId == 0 span.context().parentId == "0"
span.context().tags["http.url"] == "http://localhost:$port/param/asdf1234/" span.context().tags["http.url"] == "http://localhost:$port/param/asdf1234/"
span.context().tags["http.method"] == "GET" span.context().tags["http.method"] == "GET"
span.context().tags["span.kind"] == "server" span.context().tags["span.kind"] == "server"
@ -72,7 +72,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span0.context().resourceName == "404" span0.context().resourceName == "404"
span0.context().spanType == DDSpanTypes.WEB_SERVLET span0.context().spanType == DDSpanTypes.WEB_SERVLET
!span0.context().getErrorFlag() !span0.context().getErrorFlag()
span0.context().parentId == 0 span0.context().parentId == "0"
span0.context().tags["http.url"] == "http://localhost:$port/invalid" span0.context().tags["http.url"] == "http://localhost:$port/invalid"
span0.context().tags["http.method"] == "GET" span0.context().tags["http.method"] == "GET"
span0.context().tags["span.kind"] == "server" span0.context().tags["span.kind"] == "server"
@ -92,7 +92,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span1.context().resourceName == "404" span1.context().resourceName == "404"
span1.context().spanType == DDSpanTypes.WEB_SERVLET span1.context().spanType == DDSpanTypes.WEB_SERVLET
!span1.context().getErrorFlag() !span1.context().getErrorFlag()
span1.context().parentId == 0 span1.context().parentId == "0"
span1.context().tags["http.url"] == "http://localhost:$port/error" span1.context().tags["http.url"] == "http://localhost:$port/error"
span1.context().tags["http.method"] == "GET" span1.context().tags["http.method"] == "GET"
span1.context().tags["span.kind"] == "server" span1.context().tags["span.kind"] == "server"
@ -123,7 +123,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span0.context().resourceName == "GET /error/{parameter}/" span0.context().resourceName == "GET /error/{parameter}/"
span0.context().spanType == DDSpanTypes.WEB_SERVLET span0.context().spanType == DDSpanTypes.WEB_SERVLET
span0.context().getErrorFlag() span0.context().getErrorFlag()
span0.context().parentId == 0 span0.context().parentId == "0"
span0.context().tags["http.url"] == "http://localhost:$port/error/qwerty/" span0.context().tags["http.url"] == "http://localhost:$port/error/qwerty/"
span0.context().tags["http.method"] == "GET" span0.context().tags["http.method"] == "GET"
span0.context().tags["span.kind"] == "server" span0.context().tags["span.kind"] == "server"
@ -146,7 +146,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span1.context().operationName == "servlet.request" span1.context().operationName == "servlet.request"
span1.context().resourceName == "GET /error" span1.context().resourceName == "GET /error"
span1.context().spanType == DDSpanTypes.WEB_SERVLET span1.context().spanType == DDSpanTypes.WEB_SERVLET
span1.context().parentId == 0 span1.context().parentId == "0"
span1.context().tags["http.url"] == "http://localhost:$port/error" span1.context().tags["http.url"] == "http://localhost:$port/error"
span1.context().tags["http.method"] == "GET" span1.context().tags["http.method"] == "GET"
span1.context().tags["span.kind"] == "server" span1.context().tags["span.kind"] == "server"
@ -173,7 +173,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span.context().resourceName == "POST /validated" span.context().resourceName == "POST /validated"
span.context().spanType == DDSpanTypes.WEB_SERVLET span.context().spanType == DDSpanTypes.WEB_SERVLET
!span.context().getErrorFlag() !span.context().getErrorFlag()
span.context().parentId == 0 span.context().parentId == "0"
span.context().tags["http.url"] == "http://localhost:$port/validated" span.context().tags["http.url"] == "http://localhost:$port/validated"
span.context().tags["http.method"] == "POST" span.context().tags["http.method"] == "POST"
span.context().tags["span.kind"] == "server" span.context().tags["span.kind"] == "server"
@ -204,7 +204,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span0.context().resourceName == "POST /validated" span0.context().resourceName == "POST /validated"
span0.context().spanType == DDSpanTypes.WEB_SERVLET span0.context().spanType == DDSpanTypes.WEB_SERVLET
!span0.context().getErrorFlag() // This should be an error once we have the http status code decorator working. !span0.context().getErrorFlag() // This should be an error once we have the http status code decorator working.
span0.context().parentId == 0 span0.context().parentId == "0"
span0.context().tags["http.url"] == "http://localhost:$port/validated" span0.context().tags["http.url"] == "http://localhost:$port/validated"
span0.context().tags["http.method"] == "POST" span0.context().tags["http.method"] == "POST"
span0.context().tags["span.kind"] == "server" span0.context().tags["span.kind"] == "server"
@ -228,7 +228,7 @@ class SpringBootBasedTest extends AgentTestRunner {
span1.context().resourceName == "POST /error" span1.context().resourceName == "POST /error"
span1.context().spanType == DDSpanTypes.WEB_SERVLET span1.context().spanType == DDSpanTypes.WEB_SERVLET
!span1.context().getErrorFlag() !span1.context().getErrorFlag()
span1.context().parentId == 0 span1.context().parentId == "0"
span1.context().tags["http.url"] == "http://localhost:$port/error" span1.context().tags["http.url"] == "http://localhost:$port/error"
span1.context().tags["http.method"] == "POST" span1.context().tags["http.method"] == "POST"
span1.context().tags["span.kind"] == "server" span1.context().tags["span.kind"] == "server"

View File

@ -39,14 +39,14 @@ class SpanAssert {
} }
def parent() { def parent() {
assert span.parentId == 0 assert span.parentId == "0"
} }
def parentId(long parentId) { def parentId(String parentId) {
assert span.parentId == parentId assert span.parentId == parentId
} }
def traceId(long traceId) { def traceId(String traceId) {
assert span.traceId == traceId assert span.traceId == traceId
} }

View File

@ -19,7 +19,7 @@ class TraceCorrelationTest extends AgentTestRunner {
scope.close() scope.close()
then: then:
CorrelationIdentifier.traceId == 0 CorrelationIdentifier.traceId == "0"
CorrelationIdentifier.spanId == 0 CorrelationIdentifier.spanId == "0"
} }
} }

View File

@ -16,29 +16,29 @@ public class CorrelationIdentifier {
} }
} }
public static long getTraceId() { public static String getTraceId() {
return provider.get().getTraceId(); return provider.get().getTraceId();
} }
public static long getSpanId() { public static String getSpanId() {
return provider.get().getSpanId(); return provider.get().getSpanId();
} }
public interface Provider { public interface Provider {
long getTraceId(); String getTraceId();
long getSpanId(); String getSpanId();
Provider NO_OP = Provider NO_OP =
new Provider() { new Provider() {
@Override @Override
public long getTraceId() { public String getTraceId() {
return 0; return "0";
} }
@Override @Override
public long getSpanId() { public String getSpanId() {
return 0; return "0";
} }
}; };
} }

View File

@ -34,7 +34,9 @@ dependencies {
compile deps.jackson compile deps.jackson
compile deps.slf4j compile deps.slf4j
compile group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.8.2' // any higher versions seems to break ES tests with this exception:
// java.lang.NoSuchMethodError: com.fasterxml.jackson.dataformat.smile.SmileGenerator.getOutputContext()
compile group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.8.14'
testCompile deps.autoservice testCompile deps.autoservice
testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6' testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6'

View File

@ -4,11 +4,16 @@ import static io.opentracing.log.Fields.ERROR_OBJECT;
import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import datadog.trace.api.DDTags; import datadog.trace.api.DDTags;
import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.interceptor.MutableSpan;
import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.PrioritySampling;
import datadog.trace.common.util.Clock; import datadog.trace.common.util.Clock;
import io.opentracing.Span; import io.opentracing.Span;
import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -110,7 +115,7 @@ public class DDSpan implements Span, MutableSpan {
*/ */
@JsonIgnore @JsonIgnore
public final boolean isRootSpan() { public final boolean isRootSpan() {
return context.getParentId() == 0; return "0".equals(context.getParentId());
} }
@Override @Override
@ -317,17 +322,20 @@ public class DDSpan implements Span, MutableSpan {
} }
@JsonGetter("trace_id") @JsonGetter("trace_id")
public long getTraceId() { @JsonSerialize(using = UInt64IDStringSerializer.class)
public String getTraceId() {
return context.getTraceId(); return context.getTraceId();
} }
@JsonGetter("span_id") @JsonGetter("span_id")
public long getSpanId() { @JsonSerialize(using = UInt64IDStringSerializer.class)
public String getSpanId() {
return context.getSpanId(); return context.getSpanId();
} }
@JsonGetter("parent_id") @JsonGetter("parent_id")
public long getParentId() { @JsonSerialize(using = UInt64IDStringSerializer.class)
public String getParentId() {
return context.getParentId(); return context.getParentId();
} }
@ -390,4 +398,21 @@ public class DDSpan implements Span, MutableSpan {
.append(durationNano) .append(durationNano)
.toString(); .toString();
} }
protected static class UInt64IDStringSerializer extends StdSerializer<String> {
public UInt64IDStringSerializer() {
this(null);
}
public UInt64IDStringSerializer(Class<String> stringClass) {
super(stringClass);
}
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeNumber(value);
}
}
} }

View File

@ -35,9 +35,9 @@ public class DDSpanContext implements io.opentracing.SpanContext {
private final Map<String, String> baggageItems; private final Map<String, String> baggageItems;
// Not Shared with other span contexts // Not Shared with other span contexts
private final long traceId; private final String traceId;
private final long spanId; private final String spanId;
private final long parentId; private final String parentId;
/** Tags are associated to the current span, they will not propagate to the children span */ /** Tags are associated to the current span, they will not propagate to the children span */
private final Map<String, Object> tags = new ConcurrentHashMap<>(); private final Map<String, Object> tags = new ConcurrentHashMap<>();
@ -67,9 +67,9 @@ public class DDSpanContext implements io.opentracing.SpanContext {
private final long threadId = Thread.currentThread().getId(); private final long threadId = Thread.currentThread().getId();
public DDSpanContext( public DDSpanContext(
final long traceId, final String traceId,
final long spanId, final String spanId,
final long parentId, final String parentId,
final String serviceName, final String serviceName,
final String operationName, final String operationName,
final String resourceName, final String resourceName,
@ -86,6 +86,9 @@ public class DDSpanContext implements io.opentracing.SpanContext {
this.tracer = tracer; this.tracer = tracer;
this.trace = trace; this.trace = trace;
assert traceId != null;
assert spanId != null;
assert parentId != null;
this.traceId = traceId; this.traceId = traceId;
this.spanId = spanId; this.spanId = spanId;
this.parentId = parentId; this.parentId = parentId;
@ -111,15 +114,15 @@ public class DDSpanContext implements io.opentracing.SpanContext {
} }
} }
public long getTraceId() { public String getTraceId() {
return this.traceId; return this.traceId;
} }
public long getParentId() { public String getParentId() {
return this.parentId; return this.parentId;
} }
public long getSpanId() { public String getSpanId() {
return this.spanId; return this.spanId;
} }

View File

@ -465,9 +465,10 @@ public class DDTracer implements io.opentracing.Tracer {
return this; return this;
} }
private long generateNewId() { private String generateNewId() {
// TODO: expand the range of numbers generated to be from 1 to uint 64 MAX
// Ensure the generated ID is in a valid range: // Ensure the generated ID is in a valid range:
return ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE); return String.valueOf(ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE));
} }
/** /**
@ -477,9 +478,9 @@ public class DDTracer implements io.opentracing.Tracer {
* @return the context * @return the context
*/ */
private DDSpanContext buildSpanContext() { private DDSpanContext buildSpanContext() {
final long traceId; final String traceId;
final long spanId = generateNewId(); final String spanId = generateNewId();
final long parentSpanId; final String parentSpanId;
final Map<String, String> baggage; final Map<String, String> baggage;
final PendingTrace parentTrace; final PendingTrace parentTrace;
final int samplingPriority; final int samplingPriority;
@ -521,7 +522,7 @@ public class DDTracer implements io.opentracing.Tracer {
// Start a new trace // Start a new trace
} else { } else {
traceId = generateNewId(); traceId = generateNewId();
parentSpanId = 0L; parentSpanId = "0";
baggage = null; baggage = null;
parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings); parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings);
samplingPriority = PrioritySampling.UNSET; samplingPriority = PrioritySampling.UNSET;

View File

@ -22,20 +22,20 @@ public class OTTraceCorrelation implements CorrelationIdentifier.Provider {
} }
@Override @Override
public long getTraceId() { public String getTraceId() {
final Span activeSpan = tracer.activeSpan(); final Span activeSpan = tracer.activeSpan();
if (activeSpan instanceof DDSpan) { if (activeSpan instanceof DDSpan) {
return ((DDSpan) activeSpan).getTraceId(); return ((DDSpan) activeSpan).getTraceId();
} }
return 0; return "0";
} }
@Override @Override
public long getSpanId() { public String getSpanId() {
final Span activeSpan = tracer.activeSpan(); final Span activeSpan = tracer.activeSpan();
if (activeSpan instanceof DDSpan) { if (activeSpan instanceof DDSpan) {
return ((DDSpan) activeSpan).getSpanId(); return ((DDSpan) activeSpan).getSpanId();
} }
return 0; return "0";
} }
} }

View File

@ -30,7 +30,7 @@ public class PendingTrace extends ConcurrentLinkedDeque<DDSpan> {
} }
private final DDTracer tracer; private final DDTracer tracer;
private final long traceId; private final String traceId;
private final Map<String, String> serviceNameMappings; private final Map<String, String> serviceNameMappings;
// TODO: consider moving these time fields into DDTracer to ensure that traces have precise // TODO: consider moving these time fields into DDTracer to ensure that traces have precise
@ -51,7 +51,7 @@ public class PendingTrace extends ConcurrentLinkedDeque<DDSpan> {
private final AtomicBoolean isWritten = new AtomicBoolean(false); private final AtomicBoolean isWritten = new AtomicBoolean(false);
PendingTrace( PendingTrace(
final DDTracer tracer, final long traceId, final Map<String, String> serviceNameMappings) { final DDTracer tracer, final String traceId, final Map<String, String> serviceNameMappings) {
this.tracer = tracer; this.tracer = tracer;
this.traceId = traceId; this.traceId = traceId;
this.serviceNameMappings = serviceNameMappings; this.serviceNameMappings = serviceNameMappings;
@ -77,7 +77,13 @@ public class PendingTrace extends ConcurrentLinkedDeque<DDSpan> {
} }
public void registerSpan(final DDSpan span) { public void registerSpan(final DDSpan span) {
if (span.context().getTraceId() != traceId) { if (traceId == null || span.context() == null) {
log.error(
"Failed to register span ({}) due to null PendingTrace traceId or null span context",
span);
return;
}
if (!traceId.equals(span.context().getTraceId())) {
log.debug("{} - span registered for wrong trace ({})", span, traceId); log.debug("{} - span registered for wrong trace ({})", span, traceId);
return; return;
} }
@ -95,7 +101,12 @@ public class PendingTrace extends ConcurrentLinkedDeque<DDSpan> {
} }
private void expireSpan(final DDSpan span) { private void expireSpan(final DDSpan span) {
if (span.context().getTraceId() != traceId) { if (traceId == null || span.context() == null) {
log.error(
"Failed to expire span ({}) due to null PendingTrace traceId or null span context", span);
return;
}
if (!traceId.equals(span.context().getTraceId())) {
log.debug("{} - span expired for wrong trace ({})", span, traceId); log.debug("{} - span expired for wrong trace ({})", span, traceId);
return; return;
} }
@ -116,7 +127,12 @@ public class PendingTrace extends ConcurrentLinkedDeque<DDSpan> {
log.debug("{} - added to trace, but not complete.", span); log.debug("{} - added to trace, but not complete.", span);
return; return;
} }
if (traceId != span.getTraceId()) { if (traceId == null || span.context() == null) {
log.error(
"Failed to add span ({}) due to null PendingTrace traceId or null span context", span);
return;
}
if (!traceId.equals(span.getTraceId())) {
log.debug("{} - added to a mismatched trace.", span); log.debug("{} - added to a mismatched trace.", span);
return; return;
} }

View File

@ -5,16 +5,16 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public class ExtractedContext implements SpanContext { public class ExtractedContext implements SpanContext {
private final Long traceId; private final String traceId;
private final Long spanId; private final String 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 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 String traceId,
final Long spanId, final String spanId,
final int samplingPriority, final int samplingPriority,
final Map<String, String> baggage, final Map<String, String> baggage,
final Map<String, String> tags) { final Map<String, String> tags) {
@ -34,11 +34,11 @@ public class ExtractedContext implements SpanContext {
samplingPriorityLocked.set(true); samplingPriorityLocked.set(true);
} }
public Long getTraceId() { public String getTraceId() {
return traceId; return traceId;
} }
public Long getSpanId() { public String getSpanId() {
return spanId; return spanId;
} }

View File

@ -4,6 +4,7 @@ import datadog.opentracing.DDSpanContext;
import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.PrioritySampling;
import io.opentracing.propagation.TextMap; import io.opentracing.propagation.TextMap;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Collections; import java.util.Collections;
@ -15,6 +16,10 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class HTTPCodec implements Codec<TextMap> { 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 OT_BAGGAGE_PREFIX = "ot-baggage-";
private static final String TRACE_ID_KEY = "x-datadog-trace-id"; 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 SPAN_ID_KEY = "x-datadog-parent-id";
@ -48,34 +53,36 @@ public class HTTPCodec implements Codec<TextMap> {
Map<String, String> baggage = Collections.emptyMap(); Map<String, String> baggage = Collections.emptyMap();
Map<String, String> tags = Collections.emptyMap(); Map<String, String> tags = Collections.emptyMap();
Long traceId = 0L; String traceId = "0";
Long spanId = 0L; String spanId = "0";
int samplingPriority = PrioritySampling.UNSET; int samplingPriority = PrioritySampling.UNSET;
for (final Map.Entry<String, String> entry : carrier) { for (final Map.Entry<String, String> entry : carrier) {
final String key = entry.getKey().toLowerCase(); final String key = entry.getKey().toLowerCase();
if (key.equalsIgnoreCase(TRACE_ID_KEY)) { final String val = entry.getValue();
traceId = Long.parseLong(entry.getValue());
} else if (key.equalsIgnoreCase(SPAN_ID_KEY)) { if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
spanId = Long.parseLong(entry.getValue()); traceId = validateUInt64BitsID(val);
} else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
spanId = validateUInt64BitsID(val);
} else if (key.startsWith(OT_BAGGAGE_PREFIX)) { } else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
if (baggage.isEmpty()) { if (baggage.isEmpty()) {
baggage = new HashMap<>(); baggage = new HashMap<>();
} }
baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(entry.getValue())); baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), decode(val));
} else if (key.equalsIgnoreCase(SAMPLING_PRIORITY_KEY)) { } else if (SAMPLING_PRIORITY_KEY.equalsIgnoreCase(key)) {
samplingPriority = Integer.parseInt(entry.getValue()); samplingPriority = Integer.parseInt(val);
} }
if (taggedHeaders.containsKey(key)) { if (taggedHeaders.containsKey(key)) {
if (tags.isEmpty()) { if (tags.isEmpty()) {
tags = new HashMap<>(); tags = new HashMap<>();
} }
tags.put(taggedHeaders.get(key), decode(entry.getValue())); tags.put(taggedHeaders.get(key), decode(val));
} }
} }
ExtractedContext context = null; ExtractedContext context = null;
if (traceId != 0L) { if (!"0".equals(traceId)) {
context = new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags); context = new ExtractedContext(traceId, spanId, samplingPriority, baggage, tags);
context.lockSamplingPriority(); context.lockSamplingPriority();
@ -104,4 +111,27 @@ public class HTTPCodec implements Codec<TextMap> {
} }
return decoded; 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(String val) throws IllegalArgumentException {
try {
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 (NumberFormatException nfe) {
throw new IllegalArgumentException(
"Expecting a number for trace ID or span ID, but got: " + val, nfe);
}
}
} }

View File

@ -118,7 +118,7 @@ public class DDApi {
return false; return false;
} }
log.debug("Succesfully sent {} of {} traces to the DD agent.", traces.size(), totalSize); log.debug("Successfully sent {} of {} traces to the DD agent.", traces.size(), totalSize);
try { try {
if (null != responseString if (null != responseString
@ -130,7 +130,7 @@ public class DDApi {
} }
} }
} catch (final IOException e) { } catch (final IOException e) {
log.debug("failed to parse DD agent response: " + responseString, e); log.debug("Failed to parse DD agent response: " + responseString, e);
} }
return true; return true;

View File

@ -141,14 +141,14 @@ class DDSpanBuilderTest extends Specification {
def "should link to parent span"() { def "should link to parent span"() {
setup: setup:
final long spanId = 1L final String spanId = "1"
final long expectedParentId = spanId final long expectedParentId = spanId
final DDSpanContext mockedContext = mock(DDSpanContext) final DDSpanContext mockedContext = mock(DDSpanContext)
when(mockedContext.getTraceId()).thenReturn(spanId)
when(mockedContext.getSpanId()).thenReturn(spanId) when(mockedContext.getSpanId()).thenReturn(spanId)
when(mockedContext.getServiceName()).thenReturn("foo") when(mockedContext.getServiceName()).thenReturn("foo")
when(mockedContext.getTrace()).thenReturn(new PendingTrace(tracer, 1L, [:])) when(mockedContext.getTrace()).thenReturn(new PendingTrace(tracer, "1", [:]))
final String expectedName = "fakeName" final String expectedName = "fakeName"
@ -163,6 +163,7 @@ class DDSpanBuilderTest extends Specification {
expect: expect:
actualContext.getParentId() == expectedParentId actualContext.getParentId() == expectedParentId
actualContext.getTraceId() == spanId
} }
def "should inherit the DD parent attributes"() { def "should inherit the DD parent attributes"() {
@ -265,8 +266,8 @@ class DDSpanBuilderTest extends Specification {
where: where:
extractedContext | _ extractedContext | _
new ExtractedContext(1, 2, 0, [:], [:]) | _ new ExtractedContext("1", "2", 0, [:], [:]) | _
new ExtractedContext(3, 4, 1, ["asdf": "qwer"], ["zxcv": "1234"]) | _ 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"() {

View File

@ -39,9 +39,9 @@ class DDSpanSerializationTest extends Specification {
def tracer = new DDTracer(writer) def tracer = new DDTracer(writer)
final DDSpanContext context = final DDSpanContext context =
new DDSpanContext( new DDSpanContext(
1L, "1",
2L, "2",
0L, "0",
"service", "service",
"operation", "operation",
null, null,
@ -50,7 +50,7 @@ class DDSpanSerializationTest extends Specification {
false, false,
"type", "type",
tags, tags,
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
baggage.put(DDTags.THREAD_NAME, Thread.currentThread().getName()) baggage.put(DDTags.THREAD_NAME, Thread.currentThread().getName())

View File

@ -15,9 +15,9 @@ class DDSpanTest extends Specification {
setup: setup:
final DDSpanContext context = final DDSpanContext context =
new DDSpanContext( new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -26,7 +26,7 @@ class DDSpanTest extends Specification {
false, false,
"fakeType", "fakeType",
null, null,
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
final DDSpan span = new DDSpan(1L, context) final DDSpan span = new DDSpan(1L, context)

View File

@ -24,7 +24,7 @@ class OTTraceCorrelationTest extends Specification {
scope.close() scope.close()
expect: expect:
0 == traceCorrelation.getTraceId() "0" == traceCorrelation.getTraceId()
} }
def "get trace id with trace"() { def "get trace id with trace"() {
@ -37,7 +37,7 @@ class OTTraceCorrelationTest extends Specification {
scope.close() scope.close()
expect: expect:
0 == traceCorrelation.getSpanId() "0" == traceCorrelation.getSpanId()
} }
def "get span id with trace"() { def "get span id with trace"() {

View File

@ -13,9 +13,10 @@ class PendingTraceTest extends Specification {
def traceCount = tracer.traceCount def traceCount = tracer.traceCount
def traceId = System.identityHashCode(this) def traceId = System.identityHashCode(this)
String traceIdStr = String.valueOf(traceId)
@Subject @Subject
PendingTrace trace = new PendingTrace(tracer, traceId, [:]) PendingTrace trace = new PendingTrace(tracer, traceIdStr, [:])
DDSpan rootSpan = SpanFactory.newSpanOf(trace) DDSpan rootSpan = SpanFactory.newSpanOf(trace)
@ -130,7 +131,7 @@ class PendingTraceTest extends Specification {
def "register span to wrong trace fails"() { def "register span to wrong trace fails"() {
setup: setup:
def otherTrace = new PendingTrace(tracer, traceId - 10, [:]) def otherTrace = new PendingTrace(tracer, String.valueOf(traceId - 10), [:])
otherTrace.registerSpan(new DDSpan(0, rootSpan.context())) otherTrace.registerSpan(new DDSpan(0, rootSpan.context()))
expect: expect:
@ -141,7 +142,7 @@ class PendingTraceTest extends Specification {
def "add span to wrong trace fails"() { def "add span to wrong trace fails"() {
setup: setup:
def otherTrace = new PendingTrace(tracer, traceId - 10, [:]) def otherTrace = new PendingTrace(tracer, String.valueOf(traceId - 10), [:])
rootSpan.finish() rootSpan.finish()
otherTrace.addSpan(rootSpan) otherTrace.addSpan(rootSpan)

View File

@ -8,9 +8,9 @@ class SpanFactory {
def writer = new ListWriter() def writer = new ListWriter()
def tracer = new DDTracer(writer) def tracer = new DDTracer(writer)
def context = new DDSpanContext( def context = new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -19,16 +19,16 @@ class SpanFactory {
false, false,
"fakeType", "fakeType",
Collections.emptyMap(), Collections.emptyMap(),
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
return new DDSpan(timestampMicro, context) return new DDSpan(timestampMicro, context)
} }
static newSpanOf(DDTracer tracer) { static newSpanOf(DDTracer tracer) {
def context = new DDSpanContext( def context = new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -37,7 +37,7 @@ class SpanFactory {
false, false,
"fakeType", "fakeType",
Collections.emptyMap(), Collections.emptyMap(),
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
return new DDSpan(1, context) return new DDSpan(1, context)
} }
@ -45,8 +45,8 @@ class SpanFactory {
static newSpanOf(PendingTrace trace) { static newSpanOf(PendingTrace trace) {
def context = new DDSpanContext( def context = new DDSpanContext(
trace.traceId, trace.traceId,
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -64,9 +64,9 @@ class SpanFactory {
def writer = new ListWriter() def writer = new ListWriter()
def tracer = new DDTracer(writer) def tracer = new DDTracer(writer)
def context = new DDSpanContext( def context = new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
serviceName, serviceName,
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -75,7 +75,7 @@ class SpanFactory {
false, false,
"fakeType", "fakeType",
Collections.emptyMap(), Collections.emptyMap(),
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
context.setTag("env", envName) context.setTag("env", envName)
return new DDSpan(0l, context) return new DDSpan(0l, context)

View File

@ -87,9 +87,9 @@ class URLAsResourceNameTest extends Specification {
when: when:
final DDSpanContext context = final DDSpanContext context =
new DDSpanContext( new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -98,7 +98,7 @@ class URLAsResourceNameTest extends Specification {
false, false,
"fakeType", "fakeType",
tags, tags,
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
then: then:

View File

@ -10,6 +10,8 @@ import io.opentracing.propagation.TextMapInjectAdapter
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Specification import spock.lang.Specification
import static datadog.opentracing.propagation.HTTPCodec.BIG_INTEGER_UINT64_MAX
class HTTPCodecTest extends Specification { class HTTPCodecTest extends Specification {
@Shared @Shared
private static final String OT_BAGGAGE_PREFIX = "ot-baggage-" private static final String OT_BAGGAGE_PREFIX = "ot-baggage-"
@ -28,9 +30,9 @@ class HTTPCodecTest extends Specification {
def tracer = new DDTracer(writer) def tracer = new DDTracer(writer)
final DDSpanContext mockedContext = final DDSpanContext mockedContext =
new DDSpanContext( new DDSpanContext(
1L, "1",
2L, "2",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -44,7 +46,7 @@ class HTTPCodecTest extends Specification {
false, false,
"fakeType", "fakeType",
null, null,
new PendingTrace(tracer, 1L, [:]), new PendingTrace(tracer, "1", [:]),
tracer) tracer)
final Map<String, String> carrier = new HashMap<>() final Map<String, String> carrier = new HashMap<>()
@ -64,6 +66,96 @@ class HTTPCodecTest extends Specification {
PrioritySampling.SAMPLER_KEEP | _ 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:
final Map<String, String> actual = [ final Map<String, String> actual = [
@ -81,8 +173,8 @@ class HTTPCodecTest extends Specification {
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual)) final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
expect: expect:
context.getTraceId() == 1l context.getTraceId() == "1"
context.getSpanId() == 2l context.getSpanId() == "2"
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.getTags() == ["some-tag": "my-interesting-info"]
@ -93,4 +185,147 @@ class HTTPCodecTest extends Specification {
PrioritySampling.UNSET | _ PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _ PrioritySampling.SAMPLER_KEEP | _
} }
def "extract http headers with larger than Java long IDs"() {
setup:
String largeTraceId = "9523372036854775807"
String largeSpanId = "15815582334751494918"
final Map<String, String> actual = [
(TRACE_ID_KEY.toUpperCase()) : largeTraceId,
(SPAN_ID_KEY.toUpperCase()) : largeSpanId,
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
SOME_HEADER : "my-interesting-info",
]
if (samplingPriority != PrioritySampling.UNSET) {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
}
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
expect:
context.getTraceId() == largeTraceId
context.getSpanId() == largeSpanId
context.getBaggage().get("k1") == "v1"
context.getBaggage().get("k2") == "v2"
context.getTags() == ["some-tag": "my-interesting-info"]
context.getSamplingPriority() == samplingPriority
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "extract http headers with uint 64 max IDs"() {
setup:
String largeSpanId = BIG_INTEGER_UINT64_MAX.subtract(BigInteger.ONE).toString()
final Map<String, String> actual = [
(TRACE_ID_KEY.toUpperCase()) : BIG_INTEGER_UINT64_MAX.toString(),
(SPAN_ID_KEY.toUpperCase()) : BIG_INTEGER_UINT64_MAX.minus(1).toString(),
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
SOME_HEADER : "my-interesting-info",
]
if (samplingPriority != PrioritySampling.UNSET) {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
}
final ExtractedContext context = codec.extract(new TextMapExtractAdapter(actual))
expect:
context.getTraceId() == BIG_INTEGER_UINT64_MAX.toString()
context.getSpanId() == largeSpanId
context.getBaggage().get("k1") == "v1"
context.getBaggage().get("k2") == "v2"
context.getTags() == ["some-tag": "my-interesting-info"]
context.getSamplingPriority() == samplingPriority
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "extract http headers with invalid non-numeric ID"() {
setup:
final Map<String, String> actual = [
(TRACE_ID_KEY.toUpperCase()) : "traceID",
(SPAN_ID_KEY.toUpperCase()) : "spanID",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
SOME_HEADER : "my-interesting-info",
]
if (samplingPriority != PrioritySampling.UNSET) {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
}
when:
codec.extract(new TextMapExtractAdapter(actual))
then:
def iae = thrown(IllegalArgumentException)
assert iae.cause instanceof NumberFormatException
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "extract http headers with out of range trace ID"() {
setup:
String outOfRangeTraceId = BIG_INTEGER_UINT64_MAX.add(BigInteger.ONE).toString()
final Map<String, String> actual = [
(TRACE_ID_KEY.toUpperCase()) : outOfRangeTraceId,
(SPAN_ID_KEY.toUpperCase()) : "0",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
SOME_HEADER : "my-interesting-info",
]
if (samplingPriority != PrioritySampling.UNSET) {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
}
when:
codec.extract(new TextMapExtractAdapter(actual))
then:
thrown(IllegalArgumentException)
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
def "extract http headers with out of range span ID"() {
setup:
final Map<String, String> actual = [
(TRACE_ID_KEY.toUpperCase()) : "0",
(SPAN_ID_KEY.toUpperCase()) : "-1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k1"): "v1",
(OT_BAGGAGE_PREFIX.toUpperCase() + "k2"): "v2",
SOME_HEADER : "my-interesting-info",
]
if (samplingPriority != PrioritySampling.UNSET) {
actual.put(SAMPLING_PRIORITY_KEY, String.valueOf(samplingPriority))
}
when:
codec.extract(new TextMapExtractAdapter(actual))
then:
thrown(IllegalArgumentException)
where:
samplingPriority | _
PrioritySampling.UNSET | _
PrioritySampling.SAMPLER_KEEP | _
}
} }

View File

@ -17,9 +17,9 @@ class DDApiIntegrationTest {
static final WRITER = new ListWriter() static final WRITER = new ListWriter()
static final TRACER = new DDTracer(WRITER) static final TRACER = new DDTracer(WRITER)
static final CONTEXT = new DDSpanContext( static final CONTEXT = new DDSpanContext(
1L, "1",
1L, "1",
0L, "0",
"fakeService", "fakeService",
"fakeOperation", "fakeOperation",
"fakeResource", "fakeResource",
@ -28,7 +28,7 @@ class DDApiIntegrationTest {
false, false,
"fakeType", "fakeType",
Collections.emptyMap(), Collections.emptyMap(),
new PendingTrace(TRACER, 1L, [:]), new PendingTrace(TRACER, "1", [:]),
TRACER) TRACER)
def api = new DDApi(DDAgentWriter.DEFAULT_HOSTNAME, DDAgentWriter.DEFAULT_PORT, v4()) def api = new DDApi(DDAgentWriter.DEFAULT_HOSTNAME, DDAgentWriter.DEFAULT_PORT, v4())