From 09af444f529b53c91673b3d8cfdb868f0032f56a Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Wed, 8 Jan 2025 08:22:58 +0100 Subject: [PATCH] chore(ot): Remove custom scope manager support --- .../java/datadog/trace/core/CoreTracer.java | 19 +- .../CustomScopeManagerWrapper.java | 268 -------------- .../java/datadog/opentracing/DDTracer.java | 53 +-- .../datadog/opentracing/TypeConverter.java | 150 -------- .../groovy/OT31ApiTest.groovy | 32 +- .../groovy/OT33ApiTest.groovy | 31 +- .../opentracing/CustomScopeManagerTest.groovy | 350 ------------------ .../datadog/opentracing/DDTracerTest.groovy | 18 +- .../IterationSpansForkedTest.groovy | 29 +- 9 files changed, 65 insertions(+), 885 deletions(-) delete mode 100644 dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java delete mode 100644 dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index db63153921b..66440b83ac6 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -497,7 +497,6 @@ public CoreTracer build() { singleSpanSampler, injector, extractor, - scopeManager, localRootSpanTags, defaultSpanTags, serviceNameMappings, @@ -529,7 +528,6 @@ private CoreTracer( final SingleSpanSampler singleSpanSampler, final HttpCodec.Injector injector, final HttpCodec.Extractor extractor, - final AgentScopeManager scopeManager, final Map localRootSpanTags, final Map defaultSpanTags, final Map serviceNameMappings, @@ -632,16 +630,13 @@ private CoreTracer( : Monitoring.DISABLED; traceWriteTimer = performanceMonitoring.newThreadLocalTimer("trace.write"); - if (scopeManager == null) { - this.scopeManager = - new ContinuableScopeManager( - config.getScopeDepthLimit(), - config.isScopeStrictMode(), - profilingContextIntegration, - healthMetrics); - } else { - this.scopeManager = scopeManager; - } + + scopeManager = + new ContinuableScopeManager( + config.getScopeDepthLimit(), + config.isScopeStrictMode(), + profilingContextIntegration, + healthMetrics); externalAgentLauncher = new ExternalAgentLauncher(config); diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java b/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java deleted file mode 100644 index 8b2aab688d4..00000000000 --- a/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java +++ /dev/null @@ -1,268 +0,0 @@ -package datadog.opentracing; - -import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static java.util.concurrent.TimeUnit.SECONDS; - -import datadog.trace.api.Config; -import datadog.trace.bootstrap.instrumentation.api.AgentScope; -import datadog.trace.bootstrap.instrumentation.api.AgentScopeManager; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; -import datadog.trace.bootstrap.instrumentation.api.ScopeSource; -import datadog.trace.bootstrap.instrumentation.api.ScopeState; -import datadog.trace.util.AgentTaskScheduler; -import io.opentracing.Scope; -import io.opentracing.ScopeManager; -import io.opentracing.Span; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; - -/** - * Allows custom OpenTracing ScopeManagers used by CoreTracer - * - *

Normal case: - * - *

CoreTracer.scopeManager = ContextualScopeManager - * - *

DDTracer.scopeManager = OTScopeManager wrapping CoreTracer.scopeManager - * - *

Custom case: - * - *

CoreTracer.scopeManager = CustomScopeManagerWrapper wrapping passed in scopemanager - * - *

DDTracer.scopeManager = passed in scopemanager - */ -class CustomScopeManagerWrapper implements AgentScopeManager { - private static final String DD_ITERATION = "_dd.iteration"; - - private static final boolean CAN_GET_ACTIVE_SPAN; - private static final boolean CAN_GET_ACTIVE_SCOPE; - - static { - boolean canGetActiveScope = true; - boolean canGetActiveSpan = true; - try { - ScopeManager.class.getMethod("active"); - } catch (Throwable e) { - canGetActiveScope = false; - } - try { - ScopeManager.class.getMethod("activeSpan"); - } catch (Throwable e) { - canGetActiveSpan = false; - } - - CAN_GET_ACTIVE_SCOPE = canGetActiveScope; - CAN_GET_ACTIVE_SPAN = canGetActiveSpan; - } - - private final ScopeManager delegate; - private final TypeConverter converter; - - static final long iterationKeepAlive = - SECONDS.toMillis(Config.get().getScopeIterationKeepAlive()); - - volatile ConcurrentMap iterationSpans; - - CustomScopeManagerWrapper(final ScopeManager scopeManager, final TypeConverter converter) { - delegate = scopeManager; - this.converter = converter; - } - - @Override - public AgentScope activate(final AgentSpan agentSpan, final ScopeSource source) { - final Span span = converter.toSpan(agentSpan); - final Scope scope = delegate.activate(span); - return converter.toAgentScope(span, scope); - } - - @Override - public AgentScope activate( - final AgentSpan agentSpan, final ScopeSource source, boolean isAsyncPropagating) { - final Span span = converter.toSpan(agentSpan); - final Scope scope = delegate.activate(span); - final AgentScope agentScope = converter.toAgentScope(span, scope); - agentScope.setAsyncPropagation(isAsyncPropagating); - return agentScope; - } - - private Span delegateActiveSpan() { - if (CAN_GET_ACTIVE_SPAN) { - return delegate.activeSpan(); - } else { - Scope scope = delegate.active(); - return scope == null ? null : scope.span(); - } - } - - @Override - public AgentScope active() { - return converter.toAgentScope( - delegateActiveSpan(), CAN_GET_ACTIVE_SCOPE ? delegate.active() : null); - } - - @Override - public AgentSpan activeSpan() { - return converter.toAgentSpan(delegateActiveSpan()); - } - - @Override - public AgentScope.Continuation captureSpan(final AgentSpan span) { - // I can't see a better way to do this, and I don't know if this even makes sense. - try (AgentScope scope = this.activate(span, ScopeSource.INSTRUMENTATION)) { - return scope.capture(); - } - } - - @Override - public void closePrevious(final boolean finishSpan) { - Span span = delegateActiveSpan(); - if (span != null) { - AgentSpan agentSpan = converter.toAgentSpan(span); - if (agentSpan != null && agentSpan.getTag(DD_ITERATION) != null) { - if (iterationKeepAlive > 0) { - cancelIterationSpanCleanup(agentSpan); - } - if (CAN_GET_ACTIVE_SCOPE) { - delegate.active().close(); - } - if (finishSpan) { - agentSpan.finishWithEndToEnd(); - } - } - } - } - - @Override - public AgentScope activateNext(final AgentSpan agentSpan) { - agentSpan.setTag(DD_ITERATION, "true"); - Span span = converter.toSpan(agentSpan); - Scope scope = delegate.activate(span); - if (iterationKeepAlive > 0) { - scheduleIterationSpanCleanup(agentSpan); - } - return converter.toAgentScope(span, scope); - } - - @Override - public ScopeState newScopeState() { - return new CustomScopeState(); - } - - private class CustomScopeState implements ScopeState { - - private AgentSpan span = activeSpan(); - - @Override - public void activate() { - CustomScopeManagerWrapper.this.activate(span, ScopeSource.INSTRUMENTATION); - } - - @Override - public void fetchFromActive() { - span = activeSpan(); - } - } - - private void scheduleIterationSpanCleanup(final AgentSpan span) { - if (iterationSpans == null) { - synchronized (this) { - if (iterationSpans == null) { - iterationSpans = new ConcurrentHashMap(); - CustomScopeManagerWrapper.IterationCleaner.scheduleFor(iterationSpans); - } - } - } - IterationSpanStack spanStack = iterationSpans.get(Thread.currentThread()); - if (spanStack == null) { - iterationSpans.put(Thread.currentThread(), spanStack = new IterationSpanStack()); - } - spanStack.trackSpan(span); - } - - private void cancelIterationSpanCleanup(AgentSpan span) { - if (iterationSpans != null) { - IterationSpanStack spanStack = iterationSpans.get(Thread.currentThread()); - if (spanStack != null) { - spanStack.untrackSpan(span); - } - } - } - - /** Background task to clean-up spans from overdue iterations. */ - private static final class IterationCleaner - implements AgentTaskScheduler.Task> { - private static final CustomScopeManagerWrapper.IterationCleaner CLEANER = - new CustomScopeManagerWrapper.IterationCleaner(); - - public static void scheduleFor(Map iterationSpans) { - long period = Math.min(iterationKeepAlive, 10_000); - AgentTaskScheduler.INSTANCE.scheduleAtFixedRate( - CLEANER, iterationSpans, iterationKeepAlive, period, TimeUnit.MILLISECONDS); - } - - @Override - public void run(Map iterationSpans) { - Iterator> itr = iterationSpans.entrySet().iterator(); - - long cutOff = System.currentTimeMillis() - iterationKeepAlive; - - while (itr.hasNext()) { - Map.Entry entry = itr.next(); - - Thread thread = entry.getKey(); - IterationSpanStack spanStack = entry.getValue(); - - if (thread.isAlive()) { - spanStack.finishOverdueSpans(cutOff); - } else { // thread has stopped - spanStack.finishAllSpans(); - itr.remove(); - } - } - } - } - - private static final class IterationSpanStack { - private final Deque spans = new ArrayDeque<>(); - - public void trackSpan(AgentSpan span) { - synchronized (spans) { - spans.push(span); - } - } - - public void untrackSpan(AgentSpan span) { - synchronized (spans) { - spans.remove(span); - } - } - - public void finishOverdueSpans(long cutOff) { - while (true) { - AgentSpan s; - synchronized (spans) { - s = spans.peek(); - if (s == null || cutOff <= NANOSECONDS.toMillis(s.getStartTime())) { - break; // no more spans, or span started after the cut-off (keeps previous spans alive) - } - spans.poll(); - } - s.finishWithEndToEnd(); - } - } - - public void finishAllSpans() { - synchronized (spans) { - for (AgentSpan s : spans) { - s.finishWithEndToEnd(); - } - // no need to clear as this is only called when the owning thread is no longer alive - } - } - } -} 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 eb419c514a7..cffaaf38a88 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java @@ -84,7 +84,6 @@ public static class DDTracerBuilder { private Sampler sampler; private HttpCodec.Injector injector; private HttpCodec.Extractor extractor; - private ScopeManager scopeManager; private Map localRootSpanTags; private Map defaultSpanTags; private Map serviceNameMappings; @@ -125,9 +124,7 @@ public DDTracerBuilder extractor(HttpCodec.Extractor extractor) { @Deprecated public DDTracerBuilder scopeManager(ScopeManager scopeManager) { - log.warn( - "Custom ScopeManagers are deprecated and will be removed in a future release of dd-trace-ot"); - this.scopeManager = scopeManager; + log.warn("Custom ScopeManager support are no more supported"); return this; } @@ -178,7 +175,6 @@ public DDTracer build() { sampler, injector, extractor, - scopeManager, localRootSpanTags, defaultSpanTags, serviceNameMappings, @@ -323,7 +319,6 @@ private DDTracer( final Sampler sampler, final HttpCodec.Injector injector, final HttpCodec.Extractor extractor, - final ScopeManager scopeManager, final Map localRootSpanTags, final Map defaultSpanTags, final Map serviceNameMappings, @@ -351,68 +346,48 @@ private DDTracer( // Each of these are only overridden if set // Otherwise, the values retrieved from config will be overridden with null CoreTracer.CoreTracerBuilder builder = CoreTracer.builder(); - if (config != null) { - builder = builder.config(config); + builder.config(config); } - if (serviceName != null) { - builder = builder.serviceName(serviceName); + builder.serviceName(serviceName); } - if (writer != null) { - builder = builder.writer(writer); + builder.writer(writer); } - if (sampler != null) { - builder = builder.sampler(sampler); + builder.sampler(sampler); } - if (injector != null) { - builder = builder.injector(injector); + builder.injector(injector); } - if (extractor != null) { - builder = builder.extractor(extractor); - } - - if (scopeManager != null) { - this.scopeManager = scopeManager; - builder = builder.scopeManager(new CustomScopeManagerWrapper(scopeManager, converter)); + builder.extractor(extractor); } - if (localRootSpanTags != null) { - builder = builder.localRootSpanTags(localRootSpanTags); + builder.localRootSpanTags(localRootSpanTags); } - if (defaultSpanTags != null) { - builder = builder.defaultSpanTags(defaultSpanTags); + builder.defaultSpanTags(defaultSpanTags); } - if (serviceNameMappings != null) { - builder = builder.serviceNameMappings(serviceNameMappings); + builder.serviceNameMappings(serviceNameMappings); } - if (taggedHeaders != null) { - builder = builder.taggedHeaders(taggedHeaders); + builder.taggedHeaders(taggedHeaders); } - if (partialFlushMinSpans != 0) { - builder = builder.partialFlushMinSpans(partialFlushMinSpans); + builder.partialFlushMinSpans(partialFlushMinSpans); } - if (statsDClient != null) { - builder = builder.statsDClient(statsDClient); + builder.statsDClient(statsDClient); } - tracer = builder.build(); // FIXME [API] There's an unfortunate cycle between OTScopeManager and CoreTracer where they // depend on each other so CoreTracer // Perhaps api can change so that CoreTracer doesn't need to implement scope methods directly - if (scopeManager == null) { - this.scopeManager = new OTScopeManager(tracer, converter); - } + this.scopeManager = new OTScopeManager(tracer, converter); if ((config != null && config.isLogsInjectionEnabled()) || (config == null && Config.get().isLogsInjectionEnabled())) { diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java b/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java index f2982f6e884..968d748b53e 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java @@ -4,7 +4,6 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.AttachableWrapper; -import datadog.trace.bootstrap.instrumentation.api.ScopeSource; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; @@ -54,23 +53,6 @@ public OTSpan toSpan(final AgentSpan agentSpan) { return new OTSpan(agentSpan, this, logHandler); } - public AgentScope toAgentScope(final Span span, final Scope scope) { - // check both: with OT33 we could have an active span with a null scope - // because the method to retrieve the active scope was removed in OT33 - if (span == null && scope == null) { - return null; - } else if (scope instanceof OTScopeManager.OTScope) { - OTScopeManager.OTScope wrapper = (OTScopeManager.OTScope) scope; - if (wrapper.isFinishSpanOnClose()) { - return new FinishingScope(wrapper.unwrap()); - } else { - return wrapper.unwrap(); - } - } else { - return new CustomScope(span, scope); - } - } - public Scope toScope(final AgentScope scope, final boolean finishSpanOnClose) { if (scope == null) { return null; @@ -114,136 +96,4 @@ public AgentSpan.Context toContext(final SpanContext spanContext) { return AgentTracer.NoopContext.INSTANCE; } } - - /** - * Wraps an internal {@link AgentScope} to automatically finish its span when the scope is closed. - */ - static final class FinishingScope implements AgentScope { - private final AgentScope delegate; - - private FinishingScope(final AgentScope delegate) { - this.delegate = delegate; - } - - @Override - public AgentSpan span() { - return delegate.span(); - } - - @Override - public byte source() { - return delegate.source(); - } - - @Override - public void close() { - delegate.close(); - delegate.span().finish(); - } - - @Override - public Continuation capture() { - return delegate.capture(); - } - - @Override - public Continuation captureConcurrent() { - return delegate.captureConcurrent(); - } - - @Override - public boolean isAsyncPropagating() { - return delegate.isAsyncPropagating(); - } - - @Override - public void setAsyncPropagation(final boolean value) { - delegate.setAsyncPropagation(value); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o instanceof FinishingScope) { - return delegate.equals(((FinishingScope) o).delegate); - } - return false; - } - - @Override - public int hashCode() { - return delegate.hashCode(); - } - } - - /** Wraps an external {@link Scope} to look like an internal {@link AgentScope} */ - final class CustomScope implements AgentScope { - private final Span span; - private final Scope scope; // may be null on OT33 as we can't retrieve the active scope - - private CustomScope(final Span span, final Scope scope) { - this.span = span; - this.scope = scope; - } - - @Override - public void close() { - if (scope != null) { - scope.close(); - } - } - - @Override - public AgentSpan span() { - return toAgentSpan(span); - } - - @Override - public byte source() { - return ScopeSource.MANUAL.id(); - } - - @Override - public Continuation capture() { - return null; - } - - @Override - public Continuation captureConcurrent() { - return null; - } - - @Override - public boolean isAsyncPropagating() { - return false; - } - - @Override - public void setAsyncPropagation(final boolean value) { - // discard setting - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o instanceof CustomScope) { - CustomScope customScope = (CustomScope) o; - if (scope != null && customScope.scope != null) { - return scope.equals(customScope.scope); - } else { - return span.equals(customScope.span); - } - } - return false; - } - - @Override - public int hashCode() { - return scope != null ? scope.hashCode() : span.hashCode(); - } - } } diff --git a/dd-trace-ot/src/ot31CompatibilityTest/groovy/OT31ApiTest.groovy b/dd-trace-ot/src/ot31CompatibilityTest/groovy/OT31ApiTest.groovy index 23df68e3922..7e3b2ab110f 100644 --- a/dd-trace-ot/src/ot31CompatibilityTest/groovy/OT31ApiTest.groovy +++ b/dd-trace-ot/src/ot31CompatibilityTest/groovy/OT31ApiTest.groovy @@ -2,10 +2,6 @@ import datadog.opentracing.DDTracer import datadog.trace.api.DDSpanId import datadog.trace.api.DDTraceId import datadog.trace.api.internal.util.LongStringUtils -import io.opentracing.util.ThreadLocalScopeManager - -import static datadog.trace.api.sampling.PrioritySampling.* -import static datadog.trace.api.sampling.SamplingMechanism.* import datadog.trace.common.writer.ListWriter import datadog.trace.core.DDSpan import datadog.trace.test.util.DDSpecification @@ -16,6 +12,14 @@ import spock.lang.Subject import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces import static datadog.trace.agent.test.utils.TraceUtils.basicSpan +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP +import static datadog.trace.api.sampling.PrioritySampling.UNSET +import static datadog.trace.api.sampling.PrioritySampling.USER_DROP +import static datadog.trace.api.sampling.PrioritySampling.USER_KEEP +import static datadog.trace.api.sampling.SamplingMechanism.AGENT_RATE +import static datadog.trace.api.sampling.SamplingMechanism.DEFAULT +import static datadog.trace.api.sampling.SamplingMechanism.MANUAL // This test focuses on things that are different between OpenTracing API 0.31.0 and 0.32.0 class OT31ApiTest extends DDSpecification { @@ -77,26 +81,6 @@ class OT31ApiTest extends DDSpecification { finishSpan << [true, false] } - def "test custom scopemanager"() { - setup: - def customTracer = DDTracer.builder().writer(writer).scopeManager(new ThreadLocalScopeManager()).build() - def coreTracer = customTracer.tracer - - when: - def span = customTracer.buildSpan("some name").start() - def scope = customTracer.scopeManager().activate(span, false) - - then: - customTracer.scopeManager().active().span().delegate == span.delegate - coreTracer.activeScope().span() == span.delegate - coreTracer.activeSpan() == span.delegate - - cleanup: - scope.close() - span.finish() - customTracer.close() - } - def "test inject extract"() { setup: def span = tracer.buildSpan("some name").start() diff --git a/dd-trace-ot/src/ot33CompatibilityTest/groovy/OT33ApiTest.groovy b/dd-trace-ot/src/ot33CompatibilityTest/groovy/OT33ApiTest.groovy index 65902e7ca19..7fd77af215e 100644 --- a/dd-trace-ot/src/ot33CompatibilityTest/groovy/OT33ApiTest.groovy +++ b/dd-trace-ot/src/ot33CompatibilityTest/groovy/OT33ApiTest.groovy @@ -8,13 +8,18 @@ import datadog.trace.test.util.DDSpecification import io.opentracing.Tracer import io.opentracing.propagation.Format import io.opentracing.propagation.TextMap -import io.opentracing.util.ThreadLocalScopeManager import spock.lang.Subject import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces import static datadog.trace.agent.test.utils.TraceUtils.basicSpan -import static datadog.trace.api.sampling.PrioritySampling.* -import static datadog.trace.api.sampling.SamplingMechanism.* +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP +import static datadog.trace.api.sampling.PrioritySampling.UNSET +import static datadog.trace.api.sampling.PrioritySampling.USER_DROP +import static datadog.trace.api.sampling.PrioritySampling.USER_KEEP +import static datadog.trace.api.sampling.SamplingMechanism.AGENT_RATE +import static datadog.trace.api.sampling.SamplingMechanism.DEFAULT +import static datadog.trace.api.sampling.SamplingMechanism.MANUAL // This test focuses on things that are different between OpenTracing API 0.32.0 and 0.33.0 class OT33ApiTest extends DDSpecification { @@ -66,26 +71,6 @@ class OT33ApiTest extends DDSpecification { span.finish() } - def "test custom scopemanager"() { - setup: - def customTracer = DDTracer.builder().writer(writer).scopeManager(new ThreadLocalScopeManager()).build() - def coreTracer = customTracer.tracer - - when: - def span = customTracer.buildSpan("some name").start() - def scope = customTracer.scopeManager().activate(span) - - then: - customTracer.activeSpan().delegate == span.delegate - coreTracer.activeScope().span() == span.delegate - coreTracer.activeSpan() == span.delegate - - cleanup: - scope.close() - span.finish() - customTracer.close() - } - def "test inject extract"() { setup: def span = tracer.buildSpan("some name").start() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy deleted file mode 100644 index 11a163915c7..00000000000 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy +++ /dev/null @@ -1,350 +0,0 @@ -package datadog.opentracing - -import datadog.trace.api.DDTags -import datadog.trace.bootstrap.instrumentation.api.AgentScope -import datadog.trace.bootstrap.instrumentation.api.AgentSpan -import datadog.trace.bootstrap.instrumentation.api.ScopeSource -import datadog.trace.common.writer.ListWriter -import datadog.trace.context.TraceScope -import datadog.trace.core.CoreTracer -import datadog.trace.test.util.DDSpecification -import io.opentracing.Scope -import io.opentracing.ScopeManager -import io.opentracing.Span - -import static datadog.trace.agent.test.asserts.ListWriterAssert.assertTraces - -class CustomScopeManagerTest extends DDSpecification { - def writer = new ListWriter() - def scopeManager = new TestScopeManager() - def tracer = DDTracer.builder().writer(writer).scopeManager(scopeManager).build() - - def cleanup() { - tracer?.close() - } - - def "simple span works"() { - when: - Scope scope - try { - scope = tracer.buildSpan("someOperation") - .withTag(DDTags.SERVICE_NAME, "someService") - .startActive(true) - } finally { - scope.close() - } - - then: - assertTraces(writer, 1) { - trace(1) { - span { - serviceName "someService" - operationName "someOperation" - resourceName "someOperation" - tags { - "testScope" true - defaultTags() - } - } - } - } - } - - def "using scope manager directly"() { - when: - Span testSpan = tracer.buildSpan("someOperation") - .withTag(DDTags.SERVICE_NAME, "someService") - .start() - - Scope scope = tracer.scopeManager().activate(testSpan) - scope.close() - testSpan.finish() - - then: - tracer.scopeManager() instanceof TestScopeManager - assertTraces(writer, 1) { - trace(1) { - span { - serviceName "someService" - operationName "someOperation" - resourceName "someOperation" - tags { - "testScope" true - defaultTags() - } - } - } - } - } - - def "interactions from core"() { - given: - CoreTracer coreTracer = tracer.tracer - - when: - Span testSpan = tracer.buildSpan("someOperation") - .withTag(DDTags.SERVICE_NAME, "someService") - .start() - coreTracer.activateSpan(((OTSpan) testSpan).asAgentSpan()) - - then: - coreTracer.activeSpan() != null - def agentScope = coreTracer.activeScope() - coreTracer.activeScope().equals(agentScope) - coreTracer.activeScope().hashCode() == agentScope.hashCode() - coreTracer.activeSpan().equals(agentScope.span()) - !coreTracer.activeScope().isAsyncPropagating() - - when: - coreTracer.activeScope().setAsyncPropagation(true) - - then: - // regular scope not TraceScope from custom scope manager so this is always fals - !coreTracer.activeScope().isAsyncPropagating() - coreTracer.activeScope().capture() == null - - when: - Scope scope = tracer.scopeManager().activate(testSpan) - scope.close() - testSpan.finish() - - then: - tracer.scopeManager() instanceof TestScopeManager - assertTraces(writer, 1) { - trace(1) { - span { - serviceName "someService" - operationName "someOperation" - resourceName "someOperation" - tags { - "testScope" true - defaultTags() - } - } - } - } - } - - def "TraceScopes interactions"() { - when: - scopeManager.returnTraceScopes = true - Scope scope = tracer.buildSpan("someOperation") - .withTag(DDTags.SERVICE_NAME, "someService") - .startActive(true) - - then: - scope instanceof TraceScope - !((TraceScope) scope).isAsyncPropagating() - - when: - ((TraceScope) scope).setAsyncPropagation(true) - TraceScope.Continuation continuation = concurrent ? - ((TraceScope) scope).captureConcurrent() : ((TraceScope) scope).capture() - - then: - ((TraceScope) scope).isAsyncPropagating() - continuation != null - - when: - continuation.close() - scope.close() - - then: - tracer.scopeManager() instanceof TestScopeManager - assertTraces(writer, 1) { - trace(1) { - span { - serviceName "someService" - operationName "someOperation" - resourceName "someOperation" - tags { - "testScope" true - defaultTags() - } - } - } - } - - where: - concurrent << [false, true] - } - - def "TraceScope interactions from CoreTracer side"() { - given: - CoreTracer coreTracer = tracer.tracer - - when: - scopeManager.returnTraceScopes = true - tracer.buildSpan("someOperation") - .withTag(DDTags.SERVICE_NAME, "someService") - .startActive(true) - - then: - def agentScope = coreTracer.activeScope() - coreTracer.activeScope().equals(agentScope) - coreTracer.activeScope().hashCode() == agentScope.hashCode() - coreTracer.activeSpan().equals(agentScope.span()) - !coreTracer.activeScope().isAsyncPropagating() - - when: - coreTracer.activeScope().setAsyncPropagation(true) - TraceScope.Continuation continuation = concurrent ? - coreTracer.activeScope().captureConcurrent() : coreTracer.activeScope().capture() - - then: - coreTracer.activeScope().isAsyncPropagating() - continuation != null - - when: - continuation.cancel() - coreTracer.activeScope().close() - - then: - tracer.scopeManager() instanceof TestScopeManager - assertTraces(writer, 1) { - trace(1) { - span { - serviceName "someService" - operationName "someOperation" - resourceName "someOperation" - tags { - "testScope" true - defaultTags() - } - } - } - } - - where: - concurrent << [false, true] - } -} - -class TestScopeManager implements ScopeManager { - def converter = new TypeConverter(new DefaultLogHandler()) - boolean returnTraceScopes = false - Scope currentScope - - @Override - Scope active() { - return currentScope - } - - @Override - Span activeSpan() { - return currentScope == null ? null : currentScope.span() - } - - @Override - Scope activate(Span span) { - return activate(span, false) - } - - @Override - Scope activate(Span span, boolean finishSpanOnClose) { - if (returnTraceScopes) { - currentScope = new OTScopeManager.OTScope( - new TestAgentScope(currentScope, span), finishSpanOnClose, converter) - } else { - currentScope = new TestScope(currentScope, span, finishSpanOnClose) - } - return currentScope - } - - class TestScope implements Scope { - final Scope parent - final Span span - final boolean finishOnClose - - TestScope(Scope parent, Span span, boolean finishOnClose) { - this.parent = parent - this.span = span - this.finishOnClose = finishOnClose - } - - @Override - void close() { - span.setTag("testScope", true) // Set a tag so we know the custom scope is used - if (finishOnClose) { - span.finish() - } - currentScope = parent - } - - @Override - Span span() { - return span - } - } - - class TestAgentScope implements AgentScope { - final Scope parent - final AgentSpan agentSpan - - boolean asyncPropagating = false - - TestAgentScope(Scope parent, Span span) { - this.parent = parent - this.agentSpan = new Object() { - void setTag(String key, boolean value) { - span.setTag(key, value) - } - void finish() { - span.finish() - } - } as AgentSpan - } - - @Override - AgentSpan span() { - return agentSpan - } - - @Override - byte source() { - return ScopeSource.MANUAL.id() - } - - @Override - Continuation capture() { - return new Continuation() { - @Override - AgentScope activate() { - return TestAgentScope.this - } - - @Override - void cancel() { - } - - @Override - AgentSpan getSpan() { - return TestAgentScope.this.span() - } - } - } - - @Override - Continuation captureConcurrent() { - return capture() - } - - @Override - boolean isAsyncPropagating() { - return asyncPropagating - } - - @Override - void setAsyncPropagation(boolean value) { - asyncPropagating = value - } - - @Override - void close() { - agentSpan.setTag("testScope", true) // Set a tag so we know the custom scope is used - currentScope = parent - } - } -} - - diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerTest.groovy index f076131b057..7a3ba7b377e 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerTest.groovy @@ -1,8 +1,9 @@ package datadog.opentracing - +import datadog.trace.common.sampling.Sampler import datadog.trace.common.writer.DDAgentWriter import datadog.trace.common.writer.ListWriter +import datadog.trace.common.writer.Writer import datadog.trace.test.util.DDSpecification class DDTracerTest extends DDSpecification { @@ -18,6 +19,21 @@ class DDTracerTest extends DDSpecification { tracer.close() } + def "test deprecated tracer constructor"() { + setup: + def tracers = [] + + when: + tracers << new DDTracer() + tracers << new DDTracer('serviceName') + tracers << new DDTracer('serviceName', Mock(Writer), Mock(Sampler)) + tracers << new DDTracer('serviceName', Mock(Writer), Mock(Sampler), [:]) + tracers << new DDTracer(Mock(Writer)) + + then: + tracers.each { assert it != null } + } + def "test tracer builder with default writer"() { when: def tracer = DDTracer.builder().writer(DDAgentWriter.builder().build()).build() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/IterationSpansForkedTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/IterationSpansForkedTest.groovy index 9e67387f878..2787add8210 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/IterationSpansForkedTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/IterationSpansForkedTest.groovy @@ -7,11 +7,8 @@ import datadog.trace.core.CoreTracer import datadog.trace.core.DDSpan import datadog.trace.test.util.DDSpecification import io.opentracing.ScopeManager -import spock.util.concurrent.PollingConditions class IterationSpansForkedTest extends DDSpecification { - def conditions = new PollingConditions(timeout: 10, initialDelay: 0.1) - ListWriter writer DDTracer tracer ScopeManager scopeManager @@ -23,8 +20,8 @@ class IterationSpansForkedTest extends DDSpecification { writer = new ListWriter() statsDClient = Mock() - scopeManager = new TestScopeManager() - tracer = DDTracer.builder().writer(writer).statsDClient(statsDClient).scopeManager(scopeManager).build() + tracer = DDTracer.builder().writer(writer).statsDClient(statsDClient).build() + scopeManager = tracer.scopeManager() coreTracer = tracer.tracer } @@ -43,7 +40,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope1.span() == span1 - scopeManager.active() == scope1.scope + scopeManager.active().delegate == scope1 !spanFinished(span1) when: @@ -57,7 +54,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope2.span() == span2 - scopeManager.active() == scope2.scope + scopeManager.active().delegate == scope2 !spanFinished(span2) when: @@ -72,7 +69,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope3.span() == span3 - scopeManager.active() == scope3.scope + scopeManager.active().delegate == scope3 !spanFinished(span3) when: @@ -99,7 +96,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope1.span() == span1 - scopeManager.active() == scope1.scope + scopeManager.active().delegate == scope1 !spanFinished(span1) when: @@ -113,7 +110,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope2.span() == span2 - scopeManager.active() == scope2.scope + scopeManager.active().delegate == scope2 !spanFinished(span2) when: @@ -127,13 +124,9 @@ class IterationSpansForkedTest extends DDSpecification { and: scope3.span() == span3 - scopeManager.active() == scope3.scope + scopeManager.active().delegate == scope3 !spanFinished(span3) - when: - // 'next3' should time out & finish after 1s - conditions.eventually { assert spanFinished(span3) } - // close and finish the surrounding (non-iteration) span to complete the trace scope0.close() span0.finish() @@ -157,7 +150,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope1.span() == span1 - scopeManager.active() == scope1.scope + scopeManager.active().delegate == scope1 !spanFinished(span1) when: @@ -175,7 +168,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope1A1.span() == span1A1 - scopeManager.active() == scope1A1.scope + scopeManager.active().delegate == scope1A1 !spanFinished(span1A1) when: @@ -189,7 +182,7 @@ class IterationSpansForkedTest extends DDSpecification { and: scope1A2.span() == span1A2 - scopeManager.active() == scope1A2.scope + scopeManager.active().delegate == scope1A2 !spanFinished(span1A2) when: