diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java index 43f6efceae..da28a2bf55 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java @@ -17,6 +17,7 @@ import datadog.trace.common.sampling.Sampler; import datadog.trace.common.writer.DDAgentWriter; import datadog.trace.common.writer.DDApi; import datadog.trace.common.writer.Writer; +import io.opentracing.References; import io.opentracing.Scope; import io.opentracing.ScopeManager; import io.opentracing.Span; @@ -496,7 +497,21 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace @Override public DDSpanBuilder addReference(final String referenceType, final SpanContext spanContext) { - log.debug("`addReference` method is not implemented. Doing nothing"); + if (spanContext == null) { + return this; + } + if (!(spanContext instanceof ExtractedContext) && !(spanContext instanceof DDSpanContext)) { + log.debug( + "Expected to have a DDSpanContext or ExtractedContext but got " + + spanContext.getClass().getName()); + return this; + } + if (References.CHILD_OF.equals(referenceType) + || References.FOLLOWS_FROM.equals(referenceType)) { + return asChildOf(spanContext); + } else { + log.debug("Only support reference type of CHILD_OF and FOLLOWS_FROM"); + } return this; } diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy index f8e534294d..fb3fb34951 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy @@ -224,6 +224,130 @@ class DDSpanBuilderTest extends Specification { span.context().getResourceName() == expectedChildResourceName span.context().getSpanType() == expectedChildType } + + + def "should inherit the DD parent attributes addReference CHILD_OF"() { + setup: + def expectedName = "fakeName" + def expectedParentServiceName = "fakeServiceName" + def expectedParentResourceName = "fakeResourceName" + def expectedParentType = "fakeType" + def expectedChildServiceName = "fakeServiceName-child" + def expectedChildResourceName = "fakeResourceName-child" + def expectedChildType = "fakeType-child" + def expectedBaggageItemKey = "fakeKey" + def expectedBaggageItemValue = "fakeValue" + + final DDSpan parent = + tracer + .buildSpan(expectedName) + .withServiceName("foo") + .withResourceName(expectedParentResourceName) + .withSpanType(expectedParentType) + .start() + + parent.setBaggageItem(expectedBaggageItemKey, expectedBaggageItemValue) + + // ServiceName and SpanType are always set by the parent if they are not present in the child + DDSpan span = + tracer + .buildSpan(expectedName) + .withServiceName(expectedParentServiceName) + .addReference("child_of", parent.context()) + .start() + + println span.getBaggageItem(expectedBaggageItemKey) + println expectedBaggageItemValue + println span.context().getSpanType() + println expectedParentType + + expect: + span.getOperationName() == expectedName + span.getBaggageItem(expectedBaggageItemKey) == expectedBaggageItemValue + span.context().getServiceName() == expectedParentServiceName + span.context().getResourceName() == expectedName + span.context().getSpanType() == expectedParentType + + when: + // ServiceName and SpanType are always overwritten by the child if they are present + span = + tracer + .buildSpan(expectedName) + .withServiceName(expectedChildServiceName) + .withResourceName(expectedChildResourceName) + .withSpanType(expectedChildType) + .addReference("child_of", parent.context()) + .start() + + then: + span.getOperationName() == expectedName + span.getBaggageItem(expectedBaggageItemKey) == expectedBaggageItemValue + span.context().getServiceName() == expectedChildServiceName + span.context().getResourceName() == expectedChildResourceName + span.context().getSpanType() == expectedChildType + } + + + def "should inherit the DD parent attributes add reference FOLLOWS_FROM"() { + setup: + def expectedName = "fakeName" + def expectedParentServiceName = "fakeServiceName" + def expectedParentResourceName = "fakeResourceName" + def expectedParentType = "fakeType" + def expectedChildServiceName = "fakeServiceName-child" + def expectedChildResourceName = "fakeResourceName-child" + def expectedChildType = "fakeType-child" + def expectedBaggageItemKey = "fakeKey" + def expectedBaggageItemValue = "fakeValue" + + final DDSpan parent = + tracer + .buildSpan(expectedName) + .withServiceName("foo") + .withResourceName(expectedParentResourceName) + .withSpanType(expectedParentType) + .start() + + parent.setBaggageItem(expectedBaggageItemKey, expectedBaggageItemValue) + + // ServiceName and SpanType are always set by the parent if they are not present in the child + DDSpan span = + tracer + .buildSpan(expectedName) + .withServiceName(expectedParentServiceName) + .addReference("follows_from", parent.context()) + .start() + + println span.getBaggageItem(expectedBaggageItemKey) + println expectedBaggageItemValue + println span.context().getSpanType() + println expectedParentType + + expect: + span.getOperationName() == expectedName + span.getBaggageItem(expectedBaggageItemKey) == expectedBaggageItemValue + span.context().getServiceName() == expectedParentServiceName + span.context().getResourceName() == expectedName + span.context().getSpanType() == expectedParentType + + when: + // ServiceName and SpanType are always overwritten by the child if they are present + span = + tracer + .buildSpan(expectedName) + .withServiceName(expectedChildServiceName) + .withResourceName(expectedChildResourceName) + .withSpanType(expectedChildType) + .addReference("follows_from", parent.context()) + .start() + + then: + span.getOperationName() == expectedName + span.getBaggageItem(expectedBaggageItemKey) == expectedBaggageItemValue + span.context().getServiceName() == expectedChildServiceName + span.context().getResourceName() == expectedChildResourceName + span.context().getSpanType() == expectedChildType + } def "should track all spans in trace"() { setup: