diff --git a/src/main/java/com/datadoghq/trace/impl/SpanContext.java b/src/main/java/com/datadoghq/trace/impl/SpanContext.java index e158c82fa6..3ee15862c5 100644 --- a/src/main/java/com/datadoghq/trace/impl/SpanContext.java +++ b/src/main/java/com/datadoghq/trace/impl/SpanContext.java @@ -1,7 +1,9 @@ package com.datadoghq.trace.impl; +import java.util.Collections; import java.util.Map; +import java.util.Optional; public class SpanContext implements io.opentracing.SpanContext { @@ -34,7 +36,8 @@ public class SpanContext implements io.opentracing.SpanContext { this.traceId = traceId; this.spanId = spanId; this.parentId = parentId; - this.baggageItems = baggageItems; + Optional> baggage = Optional.ofNullable(baggageItems); + this.baggageItems = baggage.orElse(Collections.emptyMap()); this.errorFlag = errorFlag; this.metrics = metrics; @@ -44,7 +47,7 @@ public class SpanContext implements io.opentracing.SpanContext { public Iterable> baggageItems() { - return null; + return this.baggageItems.entrySet(); } public long getTraceId() { diff --git a/src/main/java/com/datadoghq/trace/impl/Tracer.java b/src/main/java/com/datadoghq/trace/impl/Tracer.java index 2734041a72..7fed08bac5 100644 --- a/src/main/java/com/datadoghq/trace/impl/Tracer.java +++ b/src/main/java/com/datadoghq/trace/impl/Tracer.java @@ -1,13 +1,11 @@ package com.datadoghq.trace.impl; +import io.opentracing.References; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.propagation.Format; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.util.*; public class Tracer implements io.opentracing.Tracer { @@ -27,27 +25,33 @@ public class Tracer implements io.opentracing.Tracer { class SpanBuilder implements io.opentracing.Tracer.SpanBuilder { private final String operationName; - private Map tags = new HashMap(); + private HashMap tags = new HashMap(); private Long timestamp; - private Optional parent = Optional.empty(); + private SpanContext parent; public SpanBuilder(String operationName) { this.operationName = operationName; } public io.opentracing.Tracer.SpanBuilder asChildOf(SpanContext spanContext) { - this.parent = Optional.ofNullable(spanContext); + this.parent = spanContext; return this; } public io.opentracing.Tracer.SpanBuilder asChildOf(Span span) { - return null; + return asChildOf(span.context()); } - public io.opentracing.Tracer.SpanBuilder addReference(String s, SpanContext spanContext) { - return null; - } + public io.opentracing.Tracer.SpanBuilder addReference(String referenceType, SpanContext spanContext) { + if (References.CHILD_OF.equals(referenceType) || References.FOLLOWS_FROM.equals(referenceType)) { + // @todo: implements the notion of referenceType, currently only link a span to a parent one + return asChildOf(spanContext); + } else { + // do nothing + return this; + } + } public io.opentracing.Tracer.SpanBuilder withTag(String tag, Number number) { return withTag(tag, (Object) number); @@ -66,7 +70,6 @@ public class Tracer implements io.opentracing.Tracer { return this; } - public io.opentracing.Tracer.SpanBuilder withStartTimestamp(long timestamp) { this.timestamp = timestamp; return this; @@ -87,11 +90,11 @@ public class Tracer implements io.opentracing.Tracer { private SpanContext buildTheSpanContext() { - SpanContext context = null; + SpanContext context; long generatedId = generateNewId(); - if (parent.isPresent()) { - com.datadoghq.trace.impl.SpanContext p = (com.datadoghq.trace.impl.SpanContext) parent.get(); + if (parent != null) { + com.datadoghq.trace.impl.SpanContext p = (com.datadoghq.trace.impl.SpanContext) parent; context = new com.datadoghq.trace.impl.SpanContext( p.getTraceId(), generatedId, @@ -121,7 +124,10 @@ public class Tracer implements io.opentracing.Tracer { } public Iterable> baggageItems() { - return null; + if (parent == null) { + return Collections.emptyList(); + } + return parent.baggageItems(); } } diff --git a/src/test/java/com/datadoghq/trace/impl/SpanBuilderTest.java b/src/test/java/com/datadoghq/trace/impl/SpanBuilderTest.java index ff813959d6..223290a85e 100644 --- a/src/test/java/com/datadoghq/trace/impl/SpanBuilderTest.java +++ b/src/test/java/com/datadoghq/trace/impl/SpanBuilderTest.java @@ -1,5 +1,6 @@ package com.datadoghq.trace.impl; +import io.opentracing.References; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -100,21 +101,87 @@ public class SpanBuilderTest { final long expectedParentId = spanId; SpanContext mockedContext = mock(SpanContext.class); + Span mockedSpan = mock(Span.class); + when(mockedSpan.context()).thenReturn(mockedContext); when(mockedContext.getSpanId()).thenReturn(spanId); final String expectedName = "fakeName"; Span span = (Span) tracer .buildSpan(expectedName) - .asChildOf(mockedContext) + .asChildOf(mockedSpan) .start(); - SpanContext actualContext = (SpanContext) span.context(); + SpanContext actualContext = (SpanContext) span.context(); assertThat(actualContext.getParentId()).isEqualTo(expectedParentId); } + @Test + public void shouldLinkViaReferenceType() { + + + final long spanId = 223L; + final long expectedParentId = spanId; + + SpanContext mockedContext = mock(SpanContext.class); + when(mockedContext.getSpanId()).thenReturn(spanId); + + final String expectedName = "fakeName"; + + + // case 1, using a CHILD_OF ref + Span span = (Span) tracer + .buildSpan(expectedName) + .addReference(References.CHILD_OF, mockedContext) + .start(); + + SpanContext actualContext = (SpanContext) span.context(); + assertThat(actualContext.getParentId()).isEqualTo(expectedParentId); + + + // case 2, using a FOLLOW_FROM ref + span = (Span) tracer + .buildSpan(expectedName) + .addReference(References.FOLLOWS_FROM, mockedContext) + .start(); + + actualContext = (SpanContext) span.context(); + assertThat(actualContext.getParentId()).isEqualTo(expectedParentId); + + // case 2, using a WFT ref, should not be linked to the previous + span = (Span) tracer + .buildSpan(expectedName) + .addReference("WTF", mockedContext) + .start(); + + actualContext = (SpanContext) span.context(); + assertThat(actualContext.getParentId()).isEqualTo(0L); + + } + + @Test + public void shouldInheritOfBaggage() { + + final String expectedName = "fakeName"; + final String expectedBaggageItemKey = "fakeKey"; + final String expectedBaggageItemValue = "fakeValue"; + + Span parent = (Span) tracer + .buildSpan(expectedName) + .start(); + + assertThat(parent.getOperationName()).isEqualTo(expectedName); + assertThat(parent.context().baggageItems()).isEmpty(); + + Span span = (Span) tracer.buildSpan(expectedName).start(); + + assertThat(span.getOperationName()).isEqualTo(expectedName); + assertThat(span.getBaggageItem(expectedBaggageItemKey)).isEqualTo(expectedBaggageItemValue); + + } + } \ No newline at end of file diff --git a/src/test/java/com/datadoghq/trace/impl/SpanTest.java b/src/test/java/com/datadoghq/trace/impl/SpanTest.java index 1878b690ab..4bd339e4d9 100644 --- a/src/test/java/com/datadoghq/trace/impl/SpanTest.java +++ b/src/test/java/com/datadoghq/trace/impl/SpanTest.java @@ -1,8 +1,42 @@ package com.datadoghq.trace.impl; +import org.junit.Test; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; public class SpanTest { + + @Test + public void shouldAddBaggageItem(){ + + + Tracer mockedTracer = mock(Tracer.class); + SpanContext mockedContext = mock(SpanContext.class); + + final String expectedBaggageItemKey = "fakeKey"; + final String expectedBaggageItemValue = "fakeValue"; + + + Span span = new Span( + mockedTracer, + "fakeName", + null, + Optional.empty(), + mockedContext + ); + + assertThat(span.context().baggageItems()).isEmpty(); + + span.setBaggageItem(expectedBaggageItemKey, expectedBaggageItemValue); + + assertThat(span.getBaggageItem(expectedBaggageItemKey)).isEqualTo(expectedBaggageItemValue); + + } + } \ No newline at end of file