diff --git a/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy b/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy index 29b2a73bfb7..de1a9a4c2f6 100644 --- a/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy +++ b/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy @@ -1,7 +1,7 @@ import datadog.trace.agent.test.AgentTestRunner import spock.lang.Timeout -@Timeout(1) +@Timeout(5) class JBossClassloadingTest extends AgentTestRunner { def "delegation property set on module load"() { setup: diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DDSpan.java b/dd-trace-ot/src/main/java/datadog/opentracing/DDSpan.java index f2f66ff675d..ebadd77606b 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDSpan.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDSpan.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; /** - * Represents an in-flight span in the opentracing system. + * Represents a period of time. Associated information is stored in the SpanContext. * *
Spans are created by the {@link DDTracer#buildSpan}. This implementation adds some features
* according to the DD agent.
@@ -28,31 +28,39 @@
public class DDSpan implements Span {
/** The context attached to the span */
- protected final DDSpanContext context;
- /** StartTime stores the creation time of the span in milliseconds */
- protected long startTimeMicro;
- /** StartTimeNano stores the only the nanoseconds for more accuracy */
- protected long startTimeNano;
- /** The duration in nanoseconds computed using the startTimeMicro and startTimeNano */
- protected long durationNano;
+ private final DDSpanContext context;
+
+ /** Creation time of the span in microseconds. Must be greater than zero. */
+ private final long startTimeMicro;
+
+ /** Creation time of span in system relative nanotime (may be negative) */
+ private final long startTimeNano;
+
+ /**
+ * The duration in nanoseconds computed using the startTimeMicro or startTimeNano. Span is
+ * considered finished when this is set.
+ */
+ private volatile long durationNano;
/**
- * A simple constructor. Currently, users have
+ * Spans should be constructed using the builder, not by calling the constructor directly.
*
- * @param timestampMicro if set, use this time instead of the auto-generated time
- * @param context the context
+ * @param timestampMicro if greater than zero, use this time instead of the current time
+ * @param context the context used for the span
*/
- protected DDSpan(final long timestampMicro, final DDSpanContext context) {
+ DDSpan(final long timestampMicro, final DDSpanContext context) {
this.context = context;
// record the start time in nano (current milli + nano delta)
- if (timestampMicro == 0L) {
+ if (timestampMicro <= 0L) {
this.startTimeMicro = Clock.currentMicroTime();
+ this.startTimeNano = Clock.currentNanoTicks();
} else {
this.startTimeMicro = timestampMicro;
+ // timestamp might have come from an external clock, so don't bother with nanotime.
+ this.startTimeNano = 0;
}
- this.startTimeNano = Clock.currentNanoTicks();
// track each span of the trace
this.context.getTrace().add(this);
@@ -60,11 +68,23 @@ protected DDSpan(final long timestampMicro, final DDSpanContext context) {
@Override
public final void finish() {
- finish(Clock.currentMicroTime());
+ if (startTimeNano != 0) {
+ if (durationNano != 0) {
+ log.debug("Span already finished: {}", this);
+ }
+ // no external clock was used, so we can rely on nanotime.
+ this.durationNano = Math.max(1, Clock.currentNanoTicks() - startTimeNano);
+ afterFinish();
+ } else {
+ finish(Clock.currentMicroTime());
+ }
}
@Override
public final void finish(final long stoptimeMicros) {
+ if (durationNano != 0) {
+ log.debug("Span already finished: {}", this);
+ }
// Ensure that duration is at least 1. Less than 1 is possible due to our use of system clock instead of nano time.
this.durationNano =
Math.max(1, TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - this.startTimeMicro));
diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy
index 25a0e5cf915..2d29df845d3 100644
--- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy
+++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy
@@ -1,29 +1,34 @@
package datadog.opentracing
import datadog.trace.common.sampling.PrioritySampling
+import datadog.trace.common.writer.ListWriter
import spock.lang.Specification
import spock.lang.Timeout
+import java.util.concurrent.TimeUnit
+
@Timeout(1)
class DDSpanTest extends Specification {
+ def writer = new ListWriter()
+ def tracer = new DDTracer(writer)
def "getters and setters"() {
setup:
final DDSpanContext context =
- new DDSpanContext(
- 1L,
- 1L,
- 0L,
- "fakeService",
- "fakeOperation",
- "fakeResource",
- PrioritySampling.UNSET,
- Collections.