Added unit tests for ActiveSpans + fixes + remove async tests about to get rebuilt
DELETE
dd-trace-examples/async-tracing/src/main/java/com/datadoghq/asyncpatterns/examples/ExampleRunnable.java
-package com.datadoghq.asyncpatterns.examples;
-
-import io.opentracing.NoopSpan;
-import io.opentracing.Span;
-import io.opentracing.Tracer;
-import io.opentracing.contrib.spanmanager.DefaultSpanManager;
-import io.opentracing.contrib.spanmanager.SpanManager;
-import io.opentracing.contrib.spanmanager.SpanManager.ManagedSpan;
-import io.opentracing.contrib.tracerresolver.TracerResolver;
-
-class ExampleRunnable implements Runnable {
- private final SpanManager spanManager;
- private final Span currentSpanFromCaller;
- public static final Tracer tracer = TracerResolver.resolveTracer();
-
- ExampleRunnable(SpanManager spanManager) {
- this(spanManager, NoopSpan.INSTANCE);
- }
-
- private ExampleRunnable(SpanManager spanManager, Span currentSpanFromCaller) {
- this.spanManager = spanManager;
- this.currentSpanFromCaller = currentSpanFromCaller;
- }
-
- ExampleRunnable withCurrentSpan() {
- return new ExampleRunnable(spanManager, spanManager.current().getSpan());
- }
-
- @Override
- public void run() {
- try (ManagedSpan parent = spanManager.activate(currentSpanFromCaller)) {
-
- myMethod();
-
- // Any background code that requires tracing
- // and may use spanManager.current().getSpan()
-
- } catch(Exception e){
- e.printStackTrace();
- }
- }
-
- public void myMethod(){
-
- try (Span appSpan = tracer.buildSpan("myMethod").asChildOf(spanManager.current().getSpan()).start(); // start appSpan
- ManagedSpan managed = spanManager.activate(appSpan)) {
-
- Thread.sleep(100);
-
- } catch(Exception e){
- e.printStackTrace();
- }
-
- }
-
-
- public static void main(String[] args) throws Throwable{
-
- SpanManager spanManager = DefaultSpanManager.getInstance();
- ExampleRunnable runnable = new ExampleRunnable(spanManager);
-
- try (Span appSpan = tracer.buildSpan("main").start(); // start appSpan
- ManagedSpan managed = spanManager.activate(appSpan)) { // update current Span
-
- Thread.sleep(100);
-
- Thread example = new Thread(runnable.withCurrentSpan());
- example.start();
- example.join();
-
- } // managed.deactivate() + appSpan.finish()
-
-
- }
-}
\ No newline at end of file

DELETE
dd-trace-examples/async-tracing/src/main/java/com/datadoghq/asyncpatterns/examples/ExampleThreadpool.java
-package com.datadoghq.asyncpatterns.examples;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import io.opentracing.Span;
-import io.opentracing.Tracer;
-import io.opentracing.contrib.spanmanager.DefaultSpanManager;
-import io.opentracing.contrib.spanmanager.SpanManager;
-import io.opentracing.contrib.spanmanager.SpanManager.ManagedSpan;
-import io.opentracing.contrib.spanmanager.concurrent.SpanPropagatingExecutorService;
-import io.opentracing.contrib.tracerresolver.TracerResolver;
-
-public class ExampleThreadpool {
-
- public static final Tracer tracer = TracerResolver.resolveTracer();
-
- public static class TracedCall implements Callable<String> {
- SpanManager spanManager = DefaultSpanManager.getInstance();
-
- @Override
- public String call() {
- try(Span appSpan = tracer.buildSpan(Thread.currentThread().getName()).asChildOf(spanManager.current().getSpan()).start();
- ManagedSpan managed = spanManager.activate(appSpan)){
- Thread.sleep(100);
- }catch(Exception e){
- e.printStackTrace();
- }
- return Thread.currentThread().getName();
- }
- }
-
- public static void main(String[] args) throws Throwable{
- SpanManager spanManager = DefaultSpanManager.getInstance();
- ExecutorService threadpool = new SpanPropagatingExecutorService(Executors.newFixedThreadPool(2), spanManager);
-
-
- try (Span appSpan = tracer.buildSpan("main").start();
- ManagedSpan current = spanManager.activate(appSpan)) {
-
- // scheduling the traced call:
- Future<String> result = threadpool.submit(new TracedCall());
- Future<String> result2 = threadpool.submit(new TracedCall());
-
- result.get();
- result2.get();
- }
- }
-}

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/DDActiveSpan.java
dd-trace/src/main/java/com/datadoghq/trace/DDActiveSpan.java
package com.datadoghq.trace;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
import io.opentracing.ActiveSpan;
/**
@@ -8,6 +10,7 @@ import io.opentracing.ActiveSpan;
public class DDActiveSpan extends DDBaseSpan<ActiveSpan> implements ActiveSpan{
protected final DDActiveSpan parent;
+ protected boolean deactivated = false;
protected DDActiveSpan(DDActiveSpan parent,DDSpan span) {
super(span.startTimeMicro, span.context());
@@ -24,14 +27,26 @@ public class DDActiveSpan extends DDBaseSpan<ActiveSpan> implements ActiveSpan{
/**
* @return the generating parent if not null
*/
+ @JsonIgnore
public DDActiveSpan getParent() {
return parent;
}
+ /**
+ * @return true if the span has already been deactivated
+ */
+ public boolean isDeactivated() {
+ return deactivated;
+ }
+
@Override
public void deactivate() {
- context().getTracer().deactivate(this);
+ DDTracer tracer = context().getTracer();
+ if(tracer!=null){
+ tracer.deactivate(this);
+ }
finish();
+ deactivated = true;
}
@Override

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/DDBaseSpan.java
dd-trace/src/main/java/com/datadoghq/trace/DDBaseSpan.java
@@ -111,7 +111,7 @@ public abstract class DDBaseSpan<S extends BaseSpan> implements BaseSpan<S> {
return false;
}
// First item of the array AND tracer set
- DDSpan first = (DDSpan) context().getTrace().get(0);
+ DDBaseSpan<?> first = context().getTrace().get(0);
return first.context().getSpanId() == this.context().getSpanId() && this.context.getTracer() != null;
}

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java
dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java
@@ -14,7 +14,7 @@ import com.datadoghq.trace.propagation.Codec;
import com.datadoghq.trace.propagation.HTTPCodec;
import com.datadoghq.trace.sampling.AllSampler;
import com.datadoghq.trace.sampling.Sampler;
-import com.datadoghq.trace.writer.DDAgentWriter;
+import com.datadoghq.trace.writer.LoggingWriter;
import com.datadoghq.trace.writer.Writer;
import io.opentracing.ActiveSpan;
@@ -53,7 +53,7 @@ public class DDTracer implements io.opentracing.Tracer {
private final CodecRegistry registry;
public static final String UNASSIGNED_DEFAULT_SERVICE_NAME = "unnamed-java-app";
- public static final Writer UNASSIGNED_WRITER = new DDAgentWriter();
+ public static final Writer UNASSIGNED_WRITER = new LoggingWriter();
public static final Sampler UNASSIGNED_SAMPLER = new AllSampler();
/**
@@ -166,6 +166,10 @@ public class DDTracer implements io.opentracing.Tracer {
* @param activeSpan
*/
protected void makeActive(DDActiveSpan activeSpan){
+ //We cannot make active a preably deactivated span
+ if(activeSpan!=null && activeSpan.isDeactivated())
+ currentActiveSpan.set(null);
+ else
currentActiveSpan.set(activeSpan);
}
@@ -183,7 +187,7 @@ public class DDTracer implements io.opentracing.Tracer {
}
@Override
- public ActiveSpan makeActive(Span span) {
+ public DDActiveSpan makeActive(Span span) {
if(!(span instanceof DDSpan))
throw new IllegalArgumentException("Cannot transform a non DDSpan into a DDActiveSpan. Provided class: "+span.getClass());
@@ -232,6 +236,9 @@ public class DDTracer implements io.opentracing.Tracer {
}
}
+ //Ensure parent inheritance
+ asChildOf(activeParent);
+
//Create the active span
DDActiveSpan activeSpan = new DDActiveSpan(activeParent,this.timestamp, buildSpanContext());
logger.debug("{} - Starting a new active span.", activeSpan);

ADD
dd-trace/src/test/java/com/datadoghq/trace/DDActiveSpanTest.java
+package com.datadoghq.trace;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.datadoghq.trace.writer.impl.ListWriter;
+
+import io.opentracing.ActiveSpan.Continuation;
+
+public class DDActiveSpanTest {
+
+ private ListWriter listWriter = new ListWriter();
+ private DDTracer ddTracer = new DDTracer(listWriter);
+
+ @Before
+ public void setUp(){
+ listWriter.start();
+ }
+
+ @Test
+ public void testContextPropagation() {
+
+ DDActiveSpan span1 = ddTracer.buildSpan("op1").startActive();
+
+ assertThat(span1.getOperationName()).isEqualTo("op1");
+ assertThat(ddTracer.activeSpan()).isEqualTo(span1);
+
+ DDActiveSpan span2 = ddTracer.buildSpan("op2").startActive();
+ assertThat(span2.getOperationName()).isEqualTo("op2");
+ assertThat(span2.getParent()).isEqualTo(span1);
+ assertThat(span2.context().getParentId()).isEqualTo(span1.getSpanId());
+ assertThat(span2.context().getTraceId()).isEqualTo(span1.getTraceId());
+ assertThat(ddTracer.activeSpan()).isEqualTo(span2);
+
+ span2.deactivate();
+ assertThat(ddTracer.activeSpan()).isEqualTo(span1);
+
+ assertThat(listWriter.getList().size()).isEqualTo(0);
+ span1.deactivate();
+ assertThat(ddTracer.activeSpan()).isNull();
+
+ assertThat(listWriter.getList().size()).isEqualTo(1);
+ assertThat(listWriter.getList().get(0).size()).isEqualTo(2);
+ assertThat(listWriter.getList().get(0).get(0)).isEqualTo(span1);
+ assertThat(listWriter.getList().get(0).get(1)).isEqualTo(span2);
+ }
+
+ @Test
+ public void testParentDeactivationFirst() {
+
+ DDActiveSpan span1 = ddTracer.buildSpan("op1").startActive();
+
+ assertThat(span1.getOperationName()).isEqualTo("op1");
+
+ DDActiveSpan span2 = ddTracer.buildSpan("op2").startActive();
+
+ assertThat(ddTracer.activeSpan()).isEqualTo(span2);
+
+ span1.deactivate();
+
+ //If parent span deactivated first => Span 2 remains the active span
+ assertThat(ddTracer.activeSpan()).isEqualTo(span2);
+
+ span2.deactivate();
+
+ //If span2 comes to be deactivated
+ assertThat(ddTracer.activeSpan()).isNull();
+
+ assertThat(listWriter.getList().size()).isEqualTo(1);
+ assertThat(listWriter.getList().get(0).size()).isEqualTo(2);
+ assertThat(listWriter.getList().get(0).get(0)).isEqualTo(span1);
+ assertThat(listWriter.getList().get(0).get(1)).isEqualTo(span2);
+ }
+
+ @Test
+ public void testContinuation() {
+ final DDActiveSpan span1 = ddTracer.buildSpan("op1").startActive();
+
+ final Continuation continuation = span1.capture();
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ assertThat(ddTracer.activeSpan()).isNull();
+ continuation.activate();
+ assertThat(ddTracer.activeSpan()).isEqualTo(span1);
+ DDActiveSpan span2 = ddTracer.buildSpan("op2").startActive();
+ assertThat(ddTracer.activeSpan()).isEqualTo(span2);
+ span2.deactivate();
+ assertThat(ddTracer.activeSpan()).isEqualTo(span1);
+ }
+ }).start();
+
+ span1.deactivate();
+ assertThat(ddTracer.activeSpan()).isNull();
+
+ assertThat(listWriter.getList().size()).isEqualTo(1);
+ assertThat(listWriter.getList().get(0).size()).isEqualTo(2);
+ assertThat(listWriter.getList().get(0).get(0)).isEqualTo(span1);
+ }
+
+ @Test
+ public void testMakeSpanActive() {
+ final DDSpan manualSpan = ddTracer.buildSpan("op1").startManual();
+
+ DDActiveSpan span1 = ddTracer.makeActive(manualSpan);
+
+ assertThat(span1.getOperationName()).isEqualTo("op1");
+ assertThat(ddTracer.activeSpan()).isEqualTo(span1);
+ assertThat(manualSpan.context()).isEqualTo(span1.context());
+ assertThat(manualSpan.startTimeNano).isEqualTo(span1.startTimeNano);
+ assertThat(manualSpan.startTimeMicro).isEqualTo(span1.startTimeMicro);
+ }
+}

RENAME
dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializerTest.java
dd-trace/src/test/java/com/datadoghq/trace/DDSpanSerializationTest.java
@@ -10,11 +10,12 @@ import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
-public class DDSpanSerializerTest {
+public class DDSpanSerializationTest {
ObjectMapper serializer;
DDSpan span;
+ DDActiveSpan activeSpan;
@Before
public void setUp() throws Exception {
@@ -42,8 +43,10 @@ public class DDSpanSerializerTest {
span = new DDSpan(
100L,
context);
-
span.finish(133L);
+
+ activeSpan = new DDActiveSpan(null,100L,context);
+ activeSpan.deactivate();
serializer = new ObjectMapper();
}
@@ -55,9 +58,16 @@ public class DDSpanSerializerTest {
// FIXME At the moment, just compare the string sizes
try {
assertThat(serializer.writeValueAsString(span).length()).isEqualTo(expected.length());
+
} catch (AssertionError e) {
assertThat(serializer.writeValueAsString(span)).isEqualTo(expected);
}
+
+ try {
+ assertThat(serializer.writeValueAsString(activeSpan).length()).isEqualTo(expected.length());
+ } catch (AssertionError e) {
+ assertThat(serializer.writeValueAsString(activeSpan)).isEqualTo(expected);
+ }
}
}

ADD
dd-trace/src/test/java/com/datadoghq/trace/writer/impl/ListWriter.java
+package com.datadoghq.trace.writer.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.datadoghq.trace.DDBaseSpan;
+import com.datadoghq.trace.writer.Writer;
+
+/**
+ *
+ */
+public class ListWriter implements Writer {
+
+ protected List<List<DDBaseSpan<?>>> list = new ArrayList<List<DDBaseSpan<?>>>();
+
+ public List<List<DDBaseSpan<?>>> getList() {
+ return list;
+ }
+
+ @Override
+ public void write(List<DDBaseSpan<?>> trace) {
+ list.add(trace);
+ }
+
+ @Override
+ public void start() {
+ list.clear();
+ }
+
+ @Override
+ public void close() {
+ list.clear();
+ }
+
+}

Added unit tests for ActiveSpans + fixes + remove async tests about to get rebuilt