adding ability to report all span in the trace
This commit is contained in:
parent
1137854b41
commit
162656296f
|
@ -1,12 +1,11 @@
|
||||||
package com.datadoghq.trace.impl;
|
package com.datadoghq.trace.impl;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.time.Clock;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import io.opentracing.Span;
|
import io.opentracing.Span;
|
||||||
import io.opentracing.SpanContext;
|
import io.opentracing.SpanContext;
|
||||||
|
|
||||||
|
@ -16,30 +15,28 @@ public class DDSpan implements io.opentracing.Span {
|
||||||
protected final Tracer tracer;
|
protected final Tracer tracer;
|
||||||
protected String operationName;
|
protected String operationName;
|
||||||
protected Map<String, Object> tags;
|
protected Map<String, Object> tags;
|
||||||
protected long startTime;
|
protected long startTimeNano;
|
||||||
protected long startTimeNano; // Only used to measure nano time durations
|
|
||||||
protected long durationNano;
|
protected long durationNano;
|
||||||
protected final DDSpanContext context;
|
protected final DDSpanContext context;
|
||||||
protected final LinkedHashSet<Span> traces;
|
protected final ArrayList<Span> trace;
|
||||||
|
|
||||||
DDSpan(
|
DDSpan(
|
||||||
Tracer tracer,
|
Tracer tracer,
|
||||||
String operationName,
|
String operationName,
|
||||||
LinkedHashSet<Span> traces,
|
ArrayList<Span> trace,
|
||||||
Map<String, Object> tags,
|
Map<String, Object> tags,
|
||||||
Long timestamp,
|
Long timestampMilliseconds,
|
||||||
DDSpanContext context) {
|
DDSpanContext context) {
|
||||||
|
|
||||||
this.tracer = tracer;
|
this.tracer = tracer;
|
||||||
this.operationName = operationName;
|
this.operationName = operationName;
|
||||||
this.traces = Optional.ofNullable(traces).orElse(new LinkedHashSet<>());
|
this.trace = Optional.ofNullable(trace).orElse(new ArrayList<>());
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
this.startTime = System.currentTimeMillis() * 1000000;
|
this.startTimeNano = Optional.ofNullable(timestampMilliseconds).orElse(Clock.systemUTC().millis()) * 1000000L;
|
||||||
this.startTimeNano = System.nanoTime();
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
// track each span of the trace
|
// track each span of the trace
|
||||||
this.traces.add(this);
|
this.trace.add(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,15 +45,19 @@ public class DDSpan implements io.opentracing.Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish() {
|
public void finish() {
|
||||||
finish(System.nanoTime());
|
finish(Clock.systemUTC().millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finish(long stopTimeMicro) {
|
public void finish(long stopTimeMillis) {
|
||||||
this.durationNano = stopTimeMicro * 1000L - startTime;
|
this.durationNano = (stopTimeMillis * 1000000L - startTimeNano);
|
||||||
if (this.isRootSpan()) {
|
if (this.isRootSpan()) {
|
||||||
this.traces.stream()
|
this.trace.stream()
|
||||||
.filter(s -> ((DDSpanContext) s.context()).getSpanId() != ((DDSpanContext) this.context()).getSpanId())
|
.filter(s -> {
|
||||||
.forEach(s -> s.finish());
|
boolean isSelf = ((DDSpanContext) s.context()).getSpanId() == ((DDSpanContext) this.context()).getSpanId();
|
||||||
|
boolean isFinished = ((DDSpan) s).getDurationNano() != 0L;
|
||||||
|
return !isSelf && !isFinished;
|
||||||
|
})
|
||||||
|
.forEach(Span::finish);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ public class DDSpan implements io.opentracing.Span {
|
||||||
|
|
||||||
@JsonGetter(value = "start")
|
@JsonGetter(value = "start")
|
||||||
public long getStartTime() {
|
public long getStartTime() {
|
||||||
return startTime;
|
return startTimeNano;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonGetter(value = "duration")
|
@JsonGetter(value = "duration")
|
||||||
|
@ -182,7 +183,8 @@ public class DDSpan implements io.opentracing.Span {
|
||||||
return context.getErrorFlag() ? 1 : 0;
|
return context.getErrorFlag() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedHashSet<Span> getTraces() {
|
@JsonIgnore
|
||||||
return traces;
|
public ArrayList<Span> getTrace() {
|
||||||
|
return trace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ public class Tracer implements io.opentracing.Tracer {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tracer.SpanBuilder withStartTimestamp(long timestamp) {
|
public Tracer.SpanBuilder withStartTimestamp(long timestampMillis) {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestampMillis;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,15 +105,15 @@ public class Tracer implements io.opentracing.Tracer {
|
||||||
DDSpanContext context = buildTheSpanContext();
|
DDSpanContext context = buildTheSpanContext();
|
||||||
logger.startNewSpan(this.operationName, context.getSpanId());
|
logger.startNewSpan(this.operationName, context.getSpanId());
|
||||||
|
|
||||||
LinkedHashSet traces = null;
|
ArrayList<Span> trace = null;
|
||||||
if (this.parent != null) {
|
if (this.parent != null) {
|
||||||
traces = parent.getTraces();
|
trace = parent.getTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DDSpan(
|
return new DDSpan(
|
||||||
Tracer.this,
|
Tracer.this,
|
||||||
this.operationName,
|
this.operationName,
|
||||||
traces,
|
trace,
|
||||||
this.tags,
|
this.tags,
|
||||||
this.timestamp,
|
this.timestamp,
|
||||||
context);
|
context);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import io.opentracing.Span;
|
||||||
|
|
||||||
public class DDApi {
|
public class DDApi {
|
||||||
|
|
||||||
protected static final String TRACES_ENDPOINT = "/v0.3/traces";
|
protected static final String TRACES_ENDPOINT = "/v0.3/trace";
|
||||||
protected static final String SERVICES_ENDPOINT = "/v0.3/services";
|
protected static final String SERVICES_ENDPOINT = "/v0.3/services";
|
||||||
|
|
||||||
protected final String host;
|
protected final String host;
|
||||||
|
@ -121,7 +121,7 @@ public class DDApi {
|
||||||
|
|
||||||
// String service = "{\"service_name\": {\"app\": \"service-name\",\"app_type\": \"web\"}}";
|
// String service = "{\"service_name\": {\"app\": \"service-name\",\"app_type\": \"web\"}}";
|
||||||
// System.out.println("Pushed service: "+api.callPUT(api.servicesEndpoint, service));
|
// System.out.println("Pushed service: "+api.callPUT(api.servicesEndpoint, service));
|
||||||
System.out.println("Pushed traces: "+api.sendTraces(traces));
|
System.out.println("Pushed trace: "+api.sendTraces(traces));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package com.datadoghq.trace.impl;
|
package com.datadoghq.trace.impl;
|
||||||
|
|
||||||
import io.opentracing.References;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -101,16 +101,16 @@ public class DDSpanBuilderTest {
|
||||||
.withStartTimestamp(expectedTimestamp)
|
.withStartTimestamp(expectedTimestamp)
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
assertThat(span.getStartTime()).isEqualTo(expectedTimestamp);
|
assertThat(span.getStartTime()).isEqualTo(expectedTimestamp * 1000000L);
|
||||||
|
|
||||||
// auto-timestamp in nanoseconds
|
// auto-timestamp in nanoseconds
|
||||||
long tick = System.nanoTime();
|
long tick = Clock.systemUTC().millis() * 1000000L;
|
||||||
span = (DDSpan) tracer
|
span = (DDSpan) tracer
|
||||||
.buildSpan(expectedName)
|
.buildSpan(expectedName)
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
// between now and now + 100ms
|
// between now and now + 100ms
|
||||||
assertThat(span.getStartTime()).isBetween(tick, tick + 100 * 1000);
|
assertThat(span.getStartTime()).isBetween(tick, tick + 100 * 1000000L);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,25 +171,37 @@ public class DDSpanBuilderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldTrackAllSpanInTrace() {
|
public void shouldTrackAllSpanInTrace() throws InterruptedException {
|
||||||
|
|
||||||
ArrayList<DDSpan> spans = new ArrayList<>();
|
ArrayList<DDSpan> spans = new ArrayList<>();
|
||||||
final int nbSamples = 10;
|
final int nbSamples = 10;
|
||||||
|
|
||||||
|
// root (aka spans[0]) is the parent
|
||||||
|
// spans[1] has a predictable duration
|
||||||
|
// others are just for fun
|
||||||
|
|
||||||
DDSpan root = (DDSpan) tracer.buildSpan("fake_O").start();
|
DDSpan root = (DDSpan) tracer.buildSpan("fake_O").start();
|
||||||
spans.add(root);
|
spans.add(root);
|
||||||
|
|
||||||
for (int i = 1; i <= 10; i++) {
|
long tickStart = Clock.systemUTC().millis();
|
||||||
|
spans.add((DDSpan) tracer.buildSpan("fake_" + 1).asChildOf(spans.get(0)).withStartTimestamp(tickStart).start());
|
||||||
|
for (int i = 2; i <= 10; i++) {
|
||||||
spans.add((DDSpan) tracer.buildSpan("fake_" + i).asChildOf(spans.get(i - 1)).start());
|
spans.add((DDSpan) tracer.buildSpan("fake_" + i).asChildOf(spans.get(i - 1)).start());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(root.getTraces()).hasSize(nbSamples + 1);
|
Thread.sleep(300);
|
||||||
assertThat(root.getTraces()).containsAll(spans);
|
long tickEnd = Clock.systemUTC().millis();
|
||||||
assertThat(spans.get((int) (Math.random() * nbSamples)).getTraces()).containsAll(spans);
|
|
||||||
|
spans.get(1).finish(tickEnd);
|
||||||
|
|
||||||
|
assertThat(root.getTrace()).hasSize(nbSamples + 1);
|
||||||
|
assertThat(root.getTrace()).containsAll(spans);
|
||||||
|
assertThat(spans.get((int) (Math.random() * nbSamples)).getTrace()).containsAll(spans);
|
||||||
|
|
||||||
root.finish();
|
root.finish();
|
||||||
//TODO Check order
|
//TODO Check order
|
||||||
//assertThat(root.getTraces()).containsExactly(spans)
|
//assertThat(root.getTrace()).containsExactly(spans)
|
||||||
|
assertThat(spans.get(1).durationNano).isEqualTo((tickEnd - tickStart) * 1000000L);
|
||||||
spans.forEach(span -> assertThat(span.getDurationNano()).isNotNull());
|
spans.forEach(span -> assertThat(span.getDurationNano()).isNotNull());
|
||||||
spans.forEach(span -> assertThat(span.getDurationNano()).isNotZero());
|
spans.forEach(span -> assertThat(span.getDurationNano()).isNotZero());
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
package com.datadoghq.trace.impl;
|
package com.datadoghq.trace.impl;
|
||||||
|
|
||||||
import io.opentracing.Span;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.floatThat;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
|
|
||||||
public class DDSpanTest {
|
public class DDSpanTest {
|
||||||
|
|
Loading…
Reference in New Issue