From 529bb1dad996a4fd9a32da9e0af59d5a4150a318 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 1 Jun 2020 12:23:05 -0400 Subject: [PATCH 1/4] Update dd-trace-ot to use internal api instead of dd-trace-core where possible. --- .../trace/agent/tooling/TracerInstaller.java | 28 ++-- .../trace/agent/test/AgentTestRunner.java | 4 +- .../agent/test/utils/GlobalTracerUtils.groovy | 28 ---- .../test/groovy/AgentTestRunnerTest.groovy | 17 +-- .../java/datadog/trace/core/CoreTracer.java | 29 +++-- .../main/java/datadog/trace/core/DDSpan.java | 5 +- .../datadog/trace/core/DDSpanContext.java | 4 + .../core/propagation/ExtractedContext.java | 2 + .../trace/core/propagation/TagContext.java | 12 ++ .../scopemanager/ContinuableScopeManager.java | 3 +- .../CustomScopeManagerWrapper.java | 4 +- .../java/datadog/opentracing/DDTracer.java | 35 +++-- .../opentracing/DefaultLogHandler.java | 16 +-- .../java/datadog/opentracing/LogHandler.java | 10 +- .../opentracing/OTExtractedContext.java | 44 ------- .../datadog/opentracing/OTScopeManager.java | 14 +- .../main/java/datadog/opentracing/OTSpan.java | 8 +- ...GenericContext.java => OTSpanContext.java} | 12 +- .../datadog/opentracing/OTTagContext.java | 50 -------- .../datadog/opentracing/TypeConverter.java | 34 +---- .../groovy/OT31ApiTest.groovy | 2 +- .../opentracing/CustomScopeManagerTest.groovy | 4 +- .../opentracing/DDTracerAPITest.groovy | 2 +- .../opentracing/OpenTracingAPITest.groovy | 4 +- .../instrumentation/api/AgentPropagation.java | 2 + .../api/AgentScopeManager.java | 6 +- .../instrumentation/api/AgentSpan.java | 15 +++ .../instrumentation/api/AgentTracer.java | 120 +++++++++++++++++- 28 files changed, 264 insertions(+), 250 deletions(-) delete mode 100644 dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/utils/GlobalTracerUtils.groovy delete mode 100644 dd-trace-ot/src/main/java/datadog/opentracing/OTExtractedContext.java rename dd-trace-ot/src/main/java/datadog/opentracing/{OTGenericContext.java => OTSpanContext.java} (72%) delete mode 100644 dd-trace-ot/src/main/java/datadog/opentracing/OTTagContext.java rename dd-trace-core/src/main/java/datadog/trace/core/scopemanager/DDScopeManager.java => internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentScopeManager.java (54%) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java index 76eda88e233..13839bcf821 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/TracerInstaller.java @@ -1,7 +1,7 @@ package datadog.trace.agent.tooling; -import datadog.opentracing.DDTracer; import datadog.trace.api.Config; +import datadog.trace.api.GlobalTracer; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.core.CoreTracer; import lombok.extern.slf4j.Slf4j; @@ -11,16 +11,8 @@ public class TracerInstaller { /** Register a global tracer if no global tracer is already registered. */ public static synchronized void installGlobalTracer() { if (Config.get().isTraceEnabled()) { - if (!io.opentracing.util.GlobalTracer.isRegistered()) { - final CoreTracer tracer = CoreTracer.builder().build(); - final DDTracer tracerOT = new DDTracer(tracer); - try { - io.opentracing.util.GlobalTracer.register(tracerOT); - datadog.trace.api.GlobalTracer.registerIfAbsent(tracer); - AgentTracer.registerIfAbsent(tracer); - } catch (final RuntimeException re) { - log.warn("Failed to register tracer: {}", tracerOT, re); - } + if (!(GlobalTracer.get() instanceof CoreTracer)) { + installGlobalTracer(CoreTracer.builder().build()); } else { log.debug("GlobalTracer already registered."); } @@ -29,12 +21,18 @@ public static synchronized void installGlobalTracer() { } } + public static void installGlobalTracer(final CoreTracer tracer) { + try { + GlobalTracer.registerIfAbsent(tracer); + AgentTracer.registerIfAbsent(tracer); + } catch (final RuntimeException re) { + log.warn("Failed to register tracer: {}", tracer, re); + } + } + public static void logVersionInfo() { VersionLogger.logAllVersions(); - log.debug( - io.opentracing.util.GlobalTracer.class.getName() - + " loaded on " - + io.opentracing.util.GlobalTracer.class.getClassLoader()); + log.debug(GlobalTracer.class.getName() + " loaded on " + GlobalTracer.class.getClassLoader()); log.debug( AgentInstaller.class.getName() + " loaded on " + AgentInstaller.class.getClassLoader()); } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.java b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.java index 9cbefc5b2d5..613004b0673 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.java +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.java @@ -4,9 +4,9 @@ import ch.qos.logback.classic.Logger; import com.google.common.collect.Sets; import datadog.trace.agent.test.asserts.ListWriterAssert; -import datadog.trace.agent.test.utils.GlobalTracerUtils; import datadog.trace.agent.tooling.AgentInstaller; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.TracerInstaller; import datadog.trace.agent.tooling.bytebuddy.matcher.AdditionalLibraryIgnoresMatcher; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; @@ -103,7 +103,7 @@ public boolean add(final List trace) { } }; TEST_TRACER = CoreTracer.builder().writer(TEST_WRITER).build(); - GlobalTracerUtils.registerOrReplaceGlobalTracer((CoreTracer) TEST_TRACER); + TracerInstaller.installGlobalTracer((CoreTracer) TEST_TRACER); } protected static TracerAPI getTestTracer() { diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/utils/GlobalTracerUtils.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/utils/GlobalTracerUtils.groovy deleted file mode 100644 index 83716e09a15..00000000000 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/utils/GlobalTracerUtils.groovy +++ /dev/null @@ -1,28 +0,0 @@ -package datadog.trace.agent.test.utils - -import datadog.opentracing.DDTracer -import datadog.trace.bootstrap.instrumentation.api.AgentTracer -import datadog.trace.core.CoreTracer - -class GlobalTracerUtils { - // FIXME [OT Split] this shares a lot of logic with TracerInstaller. Look into combining - static void registerOrReplaceGlobalTracer(final CoreTracer tracer) { - final DDTracer tracerOT = new DDTracer(tracer) - try { - datadog.trace.api.GlobalTracer.registerIfAbsent(tracer) - AgentTracer.registerIfAbsent(tracer) - io.opentracing.util.GlobalTracer.register(tracerOT) - } catch (final Exception e) { - io.opentracing.util.GlobalTracer.tracer = tracerOT - } - - if (!io.opentracing.util.GlobalTracer.isRegistered()) { - throw new RuntimeException("Unable to register the global tracer.") - } - } - - /** Get the tracer implementation out of the GlobalTracer */ - static AgentTracer.TracerAPI getUnderlyingGlobalTracer() { - return ((DDTracer) io.opentracing.util.GlobalTracer.tracer).coreTracer - } -} diff --git a/dd-java-agent/testing/src/test/groovy/AgentTestRunnerTest.groovy b/dd-java-agent/testing/src/test/groovy/AgentTestRunnerTest.groovy index 2ad2a538278..30bcdc1a27d 100644 --- a/dd-java-agent/testing/src/test/groovy/AgentTestRunnerTest.groovy +++ b/dd-java-agent/testing/src/test/groovy/AgentTestRunnerTest.groovy @@ -3,10 +3,10 @@ import datadog.trace.agent.test.AgentTestRunner import datadog.trace.agent.test.SpockRunner import datadog.trace.agent.test.utils.ClasspathUtils import datadog.trace.agent.test.utils.ConfigUtils -import datadog.trace.agent.test.utils.GlobalTracerUtils import datadog.trace.agent.tooling.Constants -import io.opentracing.Span -import io.opentracing.Tracer +import datadog.trace.api.GlobalTracer +import datadog.trace.bootstrap.instrumentation.api.AgentSpan +import datadog.trace.bootstrap.instrumentation.api.AgentTracer import spock.lang.Shared import java.lang.reflect.Field @@ -17,7 +17,6 @@ import static datadog.trace.api.Config.TRACE_CLASSES_EXCLUDE class AgentTestRunnerTest extends AgentTestRunner { private static final ClassLoader BOOTSTRAP_CLASSLOADER = null - private static final ClassLoader OT_LOADER private static final boolean AGENT_INSTALLED_IN_CLINIT @Shared @@ -28,13 +27,11 @@ class AgentTestRunnerTest extends AgentTestRunner { System.setProperty("dd." + TRACE_CLASSES_EXCLUDE, "config.exclude.packagename.*, config.exclude.SomeClass,config.exclude.SomeClass\$NestedClass") } - // when test class initializes, opentracing should be set up, but not the agent. - OT_LOADER = io.opentracing.Tracer.getClassLoader() AGENT_INSTALLED_IN_CLINIT = getAgentTransformer() != null } def setupSpec() { - sharedSpanClass = Span + sharedSpanClass = AgentSpan } def "spock runner bootstrap prefixes correct for test setup"() { @@ -60,11 +57,11 @@ class AgentTestRunnerTest extends AgentTestRunner { expect: // shared OT classes should cause no trouble sharedSpanClass.getClassLoader() == BOOTSTRAP_CLASSLOADER - Tracer.getClassLoader() == BOOTSTRAP_CLASSLOADER + AgentTracer.getClassLoader() == BOOTSTRAP_CLASSLOADER !AGENT_INSTALLED_IN_CLINIT - getTestTracer() == GlobalTracerUtils.getUnderlyingGlobalTracer() + getTestTracer() == AgentTracer.get() getAgentTransformer() != null - GlobalTracerUtils.getUnderlyingGlobalTracer() == datadog.trace.api.GlobalTracer.get() + AgentTracer.get() == GlobalTracer.get() bootstrapClassesIncorrectlyLoaded == [] } 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 0ab84c590b4..c3555b78579 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 @@ -7,6 +7,7 @@ import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; 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.AgentTracer; import datadog.trace.common.sampling.PrioritySampler; @@ -24,8 +25,6 @@ import datadog.trace.core.propagation.HttpCodec; import datadog.trace.core.propagation.TagContext; import datadog.trace.core.scopemanager.ContinuableScopeManager; -import datadog.trace.core.scopemanager.DDScopeManager; -import java.io.Closeable; import java.lang.ref.WeakReference; import java.math.BigInteger; import java.util.ArrayList; @@ -49,8 +48,7 @@ * reporting, and propagating traces */ @Slf4j -public class CoreTracer - implements Closeable, datadog.trace.api.Tracer, AgentTracer.TracerAPI, AgentPropagation { +public class CoreTracer implements AgentTracer.TracerAPI { // UINT64 max value public static final BigInteger TRACE_ID_MAX = BigInteger.valueOf(2).pow(64).subtract(BigInteger.ONE); @@ -63,7 +61,7 @@ public class CoreTracer /** Sampler defines the sampling policy in order to reduce the number of traces for instance */ final Sampler sampler; /** Scope manager is in charge of managing the scopes from which spans are created */ - final DDScopeManager scopeManager; + final AgentScopeManager scopeManager; /** A set of tags that are added only to the application's root span */ private final Map localRootSpanTags; @@ -142,7 +140,7 @@ private CoreTracer( final Sampler sampler, final HttpCodec.Injector injector, final HttpCodec.Extractor extractor, - final DDScopeManager scopeManager, + final AgentScopeManager scopeManager, final Map localRootSpanTags, final Map defaultSpanTags, final Map serviceNameMappings, @@ -252,6 +250,7 @@ private void registerClassLoader(final ClassLoader classLoader) { } } + @Override public CoreSpanBuilder buildSpan(final String operationName) { return new CoreSpanBuilder(operationName); } @@ -312,6 +311,7 @@ public void inject(final AgentSpan span, final C carrier, final Setter se inject(span.context(), carrier, setter); } + @Override public void inject(final AgentSpan.Context context, final C carrier, final Setter setter) { if (!(context instanceof DDSpanContext)) { return; @@ -325,9 +325,8 @@ public void inject(final AgentSpan.Context context, final C carrier, final S injector.inject(ddSpanContext, carrier, setter); } - // FIXME: [API] the interface has this return a AgentSpan.Context @Override - public TagContext extract(final C carrier, final Getter getter) { + public AgentSpan.Context extract(final C carrier, final Getter getter) { return extractor.extract(carrier, getter); } @@ -450,7 +449,7 @@ private static DDScopeEventFactory createScopeEventFactory() { } /** Spans are built using this builder */ - public class CoreSpanBuilder { + public class CoreSpanBuilder implements AgentTracer.SpanBuilder { private final String operationName; // Builder attributes @@ -467,6 +466,7 @@ public CoreSpanBuilder(final String operationName) { this.operationName = operationName; } + @Override public CoreSpanBuilder ignoreActiveSpan() { ignoreScope = true; return this; @@ -476,48 +476,58 @@ private DDSpan buildSpan() { return DDSpan.create(timestampMicro, buildSpanContext()); } + @Override public AgentSpan start() { final AgentSpan span = buildSpan(); return span; } + @Override public CoreSpanBuilder withTag(final String tag, final Number number) { return withTag(tag, (Object) number); } + @Override public CoreSpanBuilder withTag(final String tag, final String string) { return withTag(tag, (Object) string); } + @Override public CoreSpanBuilder withTag(final String tag, final boolean bool) { return withTag(tag, (Object) bool); } + @Override public CoreSpanBuilder withStartTimestamp(final long timestampMicroseconds) { timestampMicro = timestampMicroseconds; return this; } + @Override public CoreSpanBuilder withServiceName(final String serviceName) { this.serviceName = serviceName; return this; } + @Override public CoreSpanBuilder withResourceName(final String resourceName) { this.resourceName = resourceName; return this; } + @Override public CoreSpanBuilder withErrorFlag() { errorFlag = true; return this; } + @Override public CoreSpanBuilder withSpanType(final String spanType) { this.spanType = spanType; return this; } + @Override public CoreSpanBuilder asChildOf(final AgentSpan.Context spanContext) { parent = spanContext; return this; @@ -528,6 +538,7 @@ public CoreSpanBuilder asChildOf(final AgentSpan agentSpan) { return this; } + @Override public CoreSpanBuilder withTag(final String tag, final Object value) { if (value == null || (value instanceof String && ((String) value).isEmpty())) { tags.remove(tag); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index d08c4417728..20bfe3048ac 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -100,6 +100,7 @@ public final void finish() { } } + @Override public final void finish(final long stoptimeMicros) { finishAndAddToTrace(TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - startTimeMicro)); } @@ -198,7 +199,7 @@ public DDSpan setTag(final String tag, final Number value) { return this; } - // FIXME [API] this is not on AgentSpan or MutableSpan + @Override public DDSpan setTag(final String tag, final Object value) { context.setTag(tag, value); return this; @@ -219,10 +220,12 @@ public final DDSpanContext context() { return context; } + @Override public final String getBaggageItem(final String key) { return context.getBaggageItem(key); } + @Override public final DDSpan setBaggageItem(final String key, final String value) { context.setBaggageItem(key, value); return this; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index 58c6a383cb4..c45f23a0163 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -133,6 +133,7 @@ public DDSpanContext( this.tags.put(DDTags.THREAD_ID, threadId); } + @Override public DDId getTraceId() { return traceId; } @@ -141,6 +142,7 @@ public DDId getParentId() { return parentId; } + @Override public DDId getSpanId() { return spanId; } @@ -287,10 +289,12 @@ public Map getBaggageItems() { return baggageItems; } + @Override public Iterable> baggageItems() { return baggageItems.entrySet(); } + @Override public PendingTrace getTrace() { return trace; } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ExtractedContext.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ExtractedContext.java index 3bc0014491f..68917a9cd97 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ExtractedContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ExtractedContext.java @@ -37,10 +37,12 @@ public void lockSamplingPriority() { samplingPriorityLocked.set(true); } + @Override public DDId getTraceId() { return traceId; } + @Override public DDId getSpanId() { return spanId; } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/TagContext.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/TagContext.java index 324cbc00e09..01d829a31fe 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/TagContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/TagContext.java @@ -1,5 +1,6 @@ package datadog.trace.core.propagation; +import datadog.trace.api.DDId; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTrace; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; @@ -27,10 +28,21 @@ public Map getTags() { return tags; } + @Override public Iterable> baggageItems() { return Collections.emptyList(); } + @Override + public DDId getTraceId() { + return DDId.ZERO; + } + + @Override + public DDId getSpanId() { + return DDId.ZERO; + } + @Override public AgentTrace getTrace() { return AgentTracer.NoopAgentTrace.INSTANCE; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java b/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java index 612bd2c52d8..4008d5c8a8b 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java @@ -1,6 +1,7 @@ package datadog.trace.core.scopemanager; 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.AgentTrace; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; @@ -24,7 +25,7 @@ */ @Slf4j public class ContinuableScopeManager extends ScopeInterceptor.DelegatingInterceptor - implements DDScopeManager { + implements AgentScopeManager { static final ThreadLocal tlsScope = new ThreadLocal<>(); private final List scopeListeners; diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java b/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java index c7b76203a82..f15b87fff3f 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/CustomScopeManagerWrapper.java @@ -1,9 +1,9 @@ package datadog.opentracing; import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentScopeManager; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.context.TraceScope; -import datadog.trace.core.scopemanager.DDScopeManager; import io.opentracing.Scope; import io.opentracing.ScopeManager; import io.opentracing.Span; @@ -24,7 +24,7 @@ * *

DDTracer.scopeManager = passed in scopemanager */ -class CustomScopeManagerWrapper implements DDScopeManager { +class CustomScopeManagerWrapper implements AgentScopeManager { private final ScopeManager delegate; private final TypeConverter converter; 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 abe1381d497..66ed614b3ed 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java @@ -4,15 +4,14 @@ import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.common.sampling.Sampler; import datadog.trace.common.writer.Writer; import datadog.trace.context.ScopeListener; import datadog.trace.core.CoreTracer; -import datadog.trace.core.CoreTracer.CoreSpanBuilder; import datadog.trace.core.DDSpanContext; import datadog.trace.core.propagation.ExtractedContext; import datadog.trace.core.propagation.HttpCodec; -import datadog.trace.core.propagation.TagContext; import io.opentracing.References; import io.opentracing.Scope; import io.opentracing.ScopeManager; @@ -38,7 +37,7 @@ @Slf4j public class DDTracer implements Tracer, datadog.trace.api.Tracer { private final TypeConverter converter; - private final CoreTracer coreTracer; + private final AgentTracer.TracerAPI tracer; // FIXME [API] There's an unfortunate cycle between OTScopeManager and CoreTracer where they // each depend on each other so scopeManager can't be final @@ -177,10 +176,10 @@ public DDTracer( // Should only be used internally by TracerInstaller @Deprecated - public DDTracer(final CoreTracer coreTracer) { - this.coreTracer = coreTracer; + public DDTracer(final AgentTracer.TracerAPI tracer) { + this.tracer = tracer; converter = new TypeConverter(new DefaultLogHandler()); - scopeManager = new OTScopeManager(coreTracer, converter); + scopeManager = new OTScopeManager(tracer, converter); } @Builder @@ -259,13 +258,13 @@ private DDTracer( builder = builder.partialFlushMinSpans(partialFlushMinSpans); } - coreTracer = builder.build(); + 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(coreTracer, converter); + this.scopeManager = new OTScopeManager(tracer, converter); } } @@ -278,22 +277,22 @@ private static Map customRuntimeTags( @Override public String getTraceId() { - return coreTracer.getTraceId(); + return tracer.getTraceId(); } @Override public String getSpanId() { - return coreTracer.getSpanId(); + return tracer.getSpanId(); } @Override public boolean addTraceInterceptor(final TraceInterceptor traceInterceptor) { - return coreTracer.addTraceInterceptor(traceInterceptor); + return tracer.addTraceInterceptor(traceInterceptor); } @Override public void addScopeListener(final ScopeListener listener) { - coreTracer.addScopeListener(listener); + tracer.addScopeListener(listener); } @Override @@ -321,7 +320,7 @@ public void inject(final SpanContext spanContext, final Format format, fi if (carrier instanceof TextMapInject) { final AgentSpan.Context context = converter.toContext(spanContext); - coreTracer.inject(context, (TextMapInject) carrier, TextMapInjectSetter.INSTANCE); + tracer.inject(context, (TextMapInject) carrier, TextMapInjectSetter.INSTANCE); } else { log.debug("Unsupported format for propagation - {}", format.getClass().getName()); } @@ -330,8 +329,8 @@ public void inject(final SpanContext spanContext, final Format format, fi @Override public SpanContext extract(final Format format, final C carrier) { if (carrier instanceof TextMapExtract) { - final TagContext tagContext = - coreTracer.extract( + final AgentSpan.Context tagContext = + tracer.extract( (TextMapExtract) carrier, new TextMapExtractGetter((TextMapExtract) carrier)); return converter.toSpanContext(tagContext); @@ -343,7 +342,7 @@ public SpanContext extract(final Format format, final C carrier) { @Override public void close() { - coreTracer.close(); + tracer.close(); } private static class TextMapInjectSetter implements AgentPropagation.Setter { @@ -378,10 +377,10 @@ public String get(final TextMapExtract carrier, final String key) { } public class DDSpanBuilder implements SpanBuilder { - private final CoreSpanBuilder delegate; + private final AgentTracer.SpanBuilder delegate; public DDSpanBuilder(final String operationName) { - delegate = coreTracer.buildSpan(operationName); + delegate = tracer.buildSpan(operationName); } @Override diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DefaultLogHandler.java b/dd-trace-ot/src/main/java/datadog/opentracing/DefaultLogHandler.java index 9d8c2b88484..397174e75fb 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DefaultLogHandler.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DefaultLogHandler.java @@ -1,10 +1,10 @@ package datadog.opentracing; +import static datadog.trace.api.DDTags.ERROR_MSG; import static io.opentracing.log.Fields.ERROR_OBJECT; import static io.opentracing.log.Fields.MESSAGE; -import datadog.trace.api.DDTags; -import datadog.trace.core.DDSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import java.util.Map; import lombok.extern.slf4j.Slf4j; @@ -12,34 +12,34 @@ @Slf4j public class DefaultLogHandler implements LogHandler { @Override - public void log(final Map fields, final DDSpan span) { + public void log(final Map fields, final AgentSpan span) { extractError(fields, span); log.debug("`log` method is not implemented. Doing nothing"); } @Override public void log( - final long timestampMicroseconds, final Map fields, final DDSpan span) { + final long timestampMicroseconds, final Map fields, final AgentSpan span) { extractError(fields, span); log.debug("`log` method is not implemented. Doing nothing"); } @Override - public void log(final String event, final DDSpan span) { + public void log(final String event, final AgentSpan span) { log.debug("`log` method is not implemented. Provided log: {}", event); } @Override - public void log(final long timestampMicroseconds, final String event, final DDSpan span) { + public void log(final long timestampMicroseconds, final String event, final AgentSpan span) { log.debug("`log` method is not implemented. Provided log: {}", event); } - private void extractError(final Map map, final DDSpan span) { + private void extractError(final Map map, final AgentSpan span) { if (map.get(ERROR_OBJECT) instanceof Throwable) { final Throwable error = (Throwable) map.get(ERROR_OBJECT); span.addThrowable(error); } else if (map.get(MESSAGE) instanceof String) { - span.setTag(DDTags.ERROR_MSG, (String) map.get(MESSAGE)); + span.setTag(ERROR_MSG, (String) map.get(MESSAGE)); } } } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/LogHandler.java b/dd-trace-ot/src/main/java/datadog/opentracing/LogHandler.java index 2b453498ede..8454059cf31 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/LogHandler.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/LogHandler.java @@ -1,6 +1,6 @@ package datadog.opentracing; -import datadog.trace.core.DDSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import java.util.Map; public interface LogHandler { @@ -12,7 +12,7 @@ public interface LogHandler { * boolean values; some may also support arbitrary Objects. * @param span from which the call was made */ - void log(Map fields, DDSpan span); + void log(Map fields, AgentSpan span); /** * Handles the log implementation in the Span. @@ -22,7 +22,7 @@ public interface LogHandler { * @param fields key:value log fields. Tracer implementations should support String, numeric, and * @param span from which the call was made */ - void log(long timestampMicroseconds, Map fields, DDSpan span); + void log(long timestampMicroseconds, Map fields, AgentSpan span); /** * Handles the log implementation in the Span.. @@ -30,7 +30,7 @@ public interface LogHandler { * @param event the event value; often a stable identifier for a moment in the Span lifecycle * @param span from which the call was made */ - void log(String event, DDSpan span); + void log(String event, AgentSpan span); /** * Handles the log implementation in the Span. @@ -40,5 +40,5 @@ public interface LogHandler { * @param event the event value; often a stable identifier for a moment in the Span lifecycle * @param span from which the call was made */ - void log(long timestampMicroseconds, String event, DDSpan span); + void log(long timestampMicroseconds, String event, AgentSpan span); } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/OTExtractedContext.java b/dd-trace-ot/src/main/java/datadog/opentracing/OTExtractedContext.java deleted file mode 100644 index 947d1d9a828..00000000000 --- a/dd-trace-ot/src/main/java/datadog/opentracing/OTExtractedContext.java +++ /dev/null @@ -1,44 +0,0 @@ -package datadog.opentracing; - -import datadog.trace.core.propagation.ExtractedContext; -import java.util.Objects; - -class OTExtractedContext extends OTTagContext { - private final ExtractedContext extractedContext; - - OTExtractedContext(final ExtractedContext delegate) { - super(delegate); - this.extractedContext = delegate; - } - - @Override - public String toTraceId() { - return extractedContext.getTraceId().toString(); - } - - @Override - public String toSpanId() { - return extractedContext.getSpanId().toString(); - } - - ExtractedContext getDelegate() { - return extractedContext; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final OTExtractedContext that = (OTExtractedContext) o; - return extractedContext.equals(that.extractedContext); - } - - @Override - public int hashCode() { - return Objects.hash(extractedContext); - } -} diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/OTScopeManager.java b/dd-trace-ot/src/main/java/datadog/opentracing/OTScopeManager.java index ac5d2f54707..99321cb293e 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/OTScopeManager.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/OTScopeManager.java @@ -2,8 +2,8 @@ import datadog.trace.bootstrap.instrumentation.api.AgentScope; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.context.TraceScope; -import datadog.trace.core.CoreTracer; import io.opentracing.Scope; import io.opentracing.ScopeManager; import io.opentracing.Span; @@ -12,10 +12,10 @@ /** One of the two possible scope managers. See CustomScopeManagerWrapper */ class OTScopeManager implements ScopeManager { private final TypeConverter converter; - private final CoreTracer coreTracer; + private final AgentTracer.TracerAPI tracer; - OTScopeManager(final CoreTracer coreTracer, final TypeConverter converter) { - this.coreTracer = coreTracer; + OTScopeManager(final AgentTracer.TracerAPI tracer, final TypeConverter converter) { + this.tracer = tracer; this.converter = converter; } @@ -27,7 +27,7 @@ public Scope activate(final Span span) { @Override public Scope activate(final Span span, final boolean finishSpanOnClose) { final AgentSpan agentSpan = converter.toAgentSpan(span); - final AgentScope agentScope = coreTracer.activateSpan(agentSpan); + final AgentScope agentScope = tracer.activateSpan(agentSpan); return converter.toScope(agentScope, finishSpanOnClose); } @@ -36,12 +36,12 @@ public Scope activate(final Span span, final boolean finishSpanOnClose) { @Override public Scope active() { // WARNING... Making an assumption about finishSpanOnClose - return converter.toScope(coreTracer.activeScope(), false); + return converter.toScope(tracer.activeScope(), false); } @Override public Span activeSpan() { - return converter.toSpan(coreTracer.activeSpan()); + return converter.toSpan(tracer.activeSpan()); } static class OTScope implements Scope { diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/OTSpan.java b/dd-trace-ot/src/main/java/datadog/opentracing/OTSpan.java index 39a2e976df5..aea1a6942ad 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/OTSpan.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/OTSpan.java @@ -1,7 +1,7 @@ package datadog.opentracing; import datadog.trace.api.interceptor.MutableSpan; -import datadog.trace.core.DDSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.tag.Tag; @@ -13,11 +13,11 @@ * interact with non-ot parts of our API. */ class OTSpan implements Span, MutableSpan { - private final DDSpan delegate; + private final AgentSpan delegate; private final TypeConverter converter; private final LogHandler logHandler; - OTSpan(final DDSpan delegate, final TypeConverter converter, final LogHandler logHandler) { + OTSpan(final AgentSpan delegate, final TypeConverter converter, final LogHandler logHandler) { this.delegate = delegate; this.converter = converter; this.logHandler = logHandler; @@ -183,7 +183,7 @@ public void finish(final long finishMicros) { delegate.finish(finishMicros); } - public DDSpan getDelegate() { + public AgentSpan getDelegate() { return delegate; } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/OTGenericContext.java b/dd-trace-ot/src/main/java/datadog/opentracing/OTSpanContext.java similarity index 72% rename from dd-trace-ot/src/main/java/datadog/opentracing/OTGenericContext.java rename to dd-trace-ot/src/main/java/datadog/opentracing/OTSpanContext.java index 4eb4f7ce9e2..760d009a73c 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/OTGenericContext.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/OTSpanContext.java @@ -1,14 +1,14 @@ package datadog.opentracing; -import datadog.trace.core.DDSpanContext; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import io.opentracing.SpanContext; import java.util.Map; import java.util.Objects; -class OTGenericContext implements SpanContext { - private final DDSpanContext delegate; +class OTSpanContext implements SpanContext { + private final AgentSpan.Context delegate; - OTGenericContext(final DDSpanContext delegate) { + OTSpanContext(final AgentSpan.Context delegate) { this.delegate = delegate; } @@ -27,7 +27,7 @@ public Iterable> baggageItems() { return delegate.baggageItems(); } - DDSpanContext getDelegate() { + AgentSpan.Context getDelegate() { return delegate; } @@ -39,7 +39,7 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - final OTGenericContext that = (OTGenericContext) o; + final OTSpanContext that = (OTSpanContext) o; return delegate.equals(that.delegate); } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/OTTagContext.java b/dd-trace-ot/src/main/java/datadog/opentracing/OTTagContext.java deleted file mode 100644 index d88aa406ca6..00000000000 --- a/dd-trace-ot/src/main/java/datadog/opentracing/OTTagContext.java +++ /dev/null @@ -1,50 +0,0 @@ -package datadog.opentracing; - -import datadog.trace.core.propagation.TagContext; -import io.opentracing.SpanContext; -import java.util.Map; -import java.util.Objects; - -class OTTagContext implements SpanContext { - private final TagContext delegate; - - OTTagContext(final TagContext delegate) { - this.delegate = delegate; - } - - @Override - public String toTraceId() { - return "0"; - } - - @Override - public String toSpanId() { - return "0"; - } - - @Override - public Iterable> baggageItems() { - return delegate.baggageItems(); - } - - TagContext getDelegate() { - return delegate; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final OTTagContext that = (OTTagContext) o; - return delegate.equals(that.delegate); - } - - @Override - public int hashCode() { - return Objects.hash(delegate); - } -} 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 0bb393cd59a..4f6c8f02fdd 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/TypeConverter.java @@ -4,14 +4,9 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.context.TraceScope; -import datadog.trace.core.DDSpan; -import datadog.trace.core.DDSpanContext; -import datadog.trace.core.propagation.ExtractedContext; -import datadog.trace.core.propagation.TagContext; import io.opentracing.Scope; import io.opentracing.Span; import io.opentracing.SpanContext; -import io.opentracing.noop.NoopSpan; // Centralized place to do conversions class TypeConverter { @@ -37,12 +32,8 @@ public AgentSpan toAgentSpan(final Span span) { public Span toSpan(final AgentSpan agentSpan) { if (agentSpan == null) { return null; - } else if (agentSpan instanceof DDSpan) { - return new OTSpan((DDSpan) agentSpan, this, logHandler); - } else { - // NOOP AgentSpans - return NoopSpan.INSTANCE; } + return new OTSpan(agentSpan, this, logHandler); } // FIXME [API] Need to use the runtime type not compile-time type so "Object" is used @@ -60,31 +51,18 @@ public Scope toScope(final Object scope, final boolean finishSpanOnClose) { } } - public SpanContext toSpanContext(final DDSpanContext context) { - return new OTGenericContext(context); - } - - public SpanContext toSpanContext(final TagContext tagContext) { - if (tagContext == null) { + public SpanContext toSpanContext(final AgentSpan.Context context) { + if (context == null) { return null; - } else if (tagContext instanceof ExtractedContext) { - return new OTExtractedContext((ExtractedContext) tagContext); - } else { - return new OTTagContext(tagContext); } + return new OTSpanContext(context); } public AgentSpan.Context toContext(final SpanContext spanContext) { - // FIXME: [API] DDSpanContext, ExtractedContext, TagContext, AgentSpan.Context - // don't share a meaningful hierarchy if (spanContext == null) { return null; - } else if (spanContext instanceof OTGenericContext) { - return ((OTGenericContext) spanContext).getDelegate(); - } else if (spanContext instanceof OTExtractedContext) { - return ((OTExtractedContext) spanContext).getDelegate(); - } else if (spanContext instanceof OTTagContext) { - return ((OTTagContext) spanContext).getDelegate(); + } else if (spanContext instanceof OTSpanContext) { + return ((OTSpanContext) spanContext).getDelegate(); } else { return AgentTracer.NoopContext.INSTANCE; } diff --git a/dd-trace-ot/src/ot31CompatabilityTest/groovy/OT31ApiTest.groovy b/dd-trace-ot/src/ot31CompatabilityTest/groovy/OT31ApiTest.groovy index 46878acf5ec..356a54380de 100644 --- a/dd-trace-ot/src/ot31CompatabilityTest/groovy/OT31ApiTest.groovy +++ b/dd-trace-ot/src/ot31CompatabilityTest/groovy/OT31ApiTest.groovy @@ -88,7 +88,7 @@ class OT31ApiTest extends DDSpecification { then: extract.toTraceId() == context.toTraceId() extract.toSpanId() == context.toSpanId() - extract.extractedContext.samplingPriority == context.delegate.samplingPriority + extract.delegate.samplingPriority == context.delegate.samplingPriority } static class TextMapAdapter implements TextMap { diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy index 7a7d6de6d77..ddb5aad8339 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/CustomScopeManagerTest.groovy @@ -72,7 +72,7 @@ class CustomScopeManagerTest extends DDSpecification { def "interactions from core"() { given: - CoreTracer coreTracer = tracer.coreTracer + CoreTracer coreTracer = tracer.tracer when: Span testSpan = tracer.buildSpan("someOperation") @@ -156,7 +156,7 @@ class CustomScopeManagerTest extends DDSpecification { def "TraceScope interactions from CoreTracer side"() { given: - CoreTracer coreTracer = tracer.coreTracer + CoreTracer coreTracer = tracer.tracer when: scopeManager.returnTraceScopes = true diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerAPITest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerAPITest.groovy index 48b78005728..edc6108d728 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerAPITest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDTracerAPITest.groovy @@ -16,7 +16,7 @@ class DDTracerAPITest extends DDSpecification { when: def tracerOT = new DDTracer(DEFAULT_SERVICE_NAME, writer, sampler) - def tracer = tracerOT.coreTracer + def tracer = tracerOT.tracer then: tracer.serviceName == DEFAULT_SERVICE_NAME diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/OpenTracingAPITest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/OpenTracingAPITest.groovy index a2b4906592c..49bc699ed69 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/OpenTracingAPITest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/OpenTracingAPITest.groovy @@ -261,8 +261,8 @@ class OpenTracingAPITest extends DDSpecification { testSpan.context().toSpanId() == tracer.getSpanId() testSpan.context().toTraceId() == tracer.getTraceId() - testSpan.context().toSpanId() == tracer.coreTracer.getSpanId() - testSpan.context().toTraceId() == tracer.coreTracer.getTraceId() + testSpan.context().toSpanId() == tracer.tracer.getSpanId() + testSpan.context().toTraceId() == tracer.tracer.getTraceId() when: scope.close() diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentPropagation.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentPropagation.java index 44ed8144585..cfa745fa018 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentPropagation.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentPropagation.java @@ -8,6 +8,8 @@ public interface AgentPropagation { void inject(AgentSpan span, C carrier, Setter setter); + void inject(AgentSpan.Context context, C carrier, Setter setter); + interface Setter { void set(C carrier, String key, String value); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/DDScopeManager.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentScopeManager.java similarity index 54% rename from dd-trace-core/src/main/java/datadog/trace/core/scopemanager/DDScopeManager.java rename to internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentScopeManager.java index 97bcac3f0c4..28381f93c3a 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/scopemanager/DDScopeManager.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentScopeManager.java @@ -1,13 +1,11 @@ -package datadog.trace.core.scopemanager; +package datadog.trace.bootstrap.instrumentation.api; -import datadog.trace.bootstrap.instrumentation.api.AgentScope; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.context.TraceScope; /** * Allows custom scope managers. See OTScopeManager, CustomScopeManager, and ContextualScopeManager */ -public interface DDScopeManager { +public interface AgentScopeManager { AgentScope activate(AgentSpan span); TraceScope active(); diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java index cbe437d315f..86a521a12f7 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java @@ -2,6 +2,7 @@ import datadog.trace.api.DDId; import datadog.trace.api.interceptor.MutableSpan; +import java.util.Map; public interface AgentSpan extends MutableSpan { @@ -19,6 +20,8 @@ public interface AgentSpan extends MutableSpan { @Override AgentSpan setTag(String key, String value); + AgentSpan setTag(String key, Object value); + @Override AgentSpan setError(boolean error); @@ -33,8 +36,14 @@ public interface AgentSpan extends MutableSpan { Context context(); + String getBaggageItem(String key); + + AgentSpan setBaggageItem(String key, String value); + void finish(); + void finish(long finishMicros); + String getSpanName(); void setSpanName(String spanName); @@ -42,6 +51,12 @@ public interface AgentSpan extends MutableSpan { boolean hasResourceName(); interface Context { + DDId getTraceId(); + + DDId getSpanId(); + AgentTrace getTrace(); + + Iterable> baggageItems(); } } diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java index 842c5c0cd6b..0a3f2abca62 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java @@ -2,8 +2,10 @@ import datadog.trace.api.DDId; import datadog.trace.api.interceptor.MutableSpan; +import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.bootstrap.instrumentation.api.AgentSpan.Context; +import datadog.trace.context.ScopeListener; import datadog.trace.context.TraceScope; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -61,8 +63,14 @@ public static AgentSpan noopSpan() { private static final AtomicReference provider = new AtomicReference<>(DEFAULT); + public static boolean isRegistered() { + return provider.get() != DEFAULT; + } + public static void registerIfAbsent(final TracerAPI trace) { - provider.compareAndSet(DEFAULT, trace); + if (trace != null && trace != DEFAULT) { + provider.compareAndSet(DEFAULT, trace); + } } public static TracerAPI get() { @@ -72,7 +80,7 @@ public static TracerAPI get() { // Not intended to be constructed. private AgentTracer() {} - public interface TracerAPI { + public interface TracerAPI extends datadog.trace.api.Tracer, AgentPropagation { AgentSpan startSpan(String spanName); AgentSpan startSpan(String spanName, long startTimeMicros); @@ -90,6 +98,36 @@ public interface TracerAPI { AgentPropagation propagate(); AgentSpan noopSpan(); + + SpanBuilder buildSpan(String spanName); + + void close(); + } + + public interface SpanBuilder { + AgentSpan start(); + + SpanBuilder asChildOf(Context toContext); + + SpanBuilder ignoreActiveSpan(); + + SpanBuilder withTag(String key, String value); + + SpanBuilder withTag(String key, boolean value); + + SpanBuilder withTag(String key, Number value); + + SpanBuilder withTag(String tag, Object value); + + SpanBuilder withStartTimestamp(long microseconds); + + SpanBuilder withServiceName(String serviceName); + + SpanBuilder withResourceName(String resourceName); + + SpanBuilder withErrorFlag(); + + SpanBuilder withSpanType(String spanType); } static class NoopTracerAPI implements TracerAPI { @@ -141,6 +179,48 @@ public AgentPropagation propagate() { public AgentSpan noopSpan() { return NoopAgentSpan.INSTANCE; } + + @Override + public SpanBuilder buildSpan(final String spanName) { + return null; + } + + @Override + public void close() {} + + @Override + public String getTraceId() { + return null; + } + + @Override + public String getSpanId() { + return null; + } + + @Override + public boolean addTraceInterceptor(final TraceInterceptor traceInterceptor) { + return false; + } + + @Override + public void addScopeListener(final ScopeListener listener) {} + + @Override + public TraceScope.Continuation capture() { + return null; + } + + @Override + public void inject(final AgentSpan span, final C carrier, final Setter setter) {} + + @Override + public void inject(final Context context, final C carrier, final Setter setter) {} + + @Override + public Context extract(final C carrier, final Getter getter) { + return null; + } } public static class NoopAgentSpan implements AgentSpan { @@ -181,6 +261,11 @@ public AgentSpan setTag(final String key, final double value) { return this; } + @Override + public AgentSpan setTag(final String key, final Object value) { + return this; + } + @Override public long getStartTime() { return 0; @@ -288,9 +373,22 @@ public Context context() { return NoopContext.INSTANCE; } + @Override + public String getBaggageItem(final String key) { + return null; + } + + @Override + public AgentSpan setBaggageItem(final String key, final String value) { + return this; + } + @Override public void finish() {} + @Override + public void finish(final long finishMicros) {} + @Override public String getSpanName() { return ""; @@ -341,6 +439,9 @@ public AgentScope.Continuation capture() { @Override public void inject(final AgentSpan span, final C carrier, final Setter setter) {} + @Override + public void inject(final Context context, final C carrier, final Setter setter) {} + @Override public Context extract(final C carrier, final Getter getter) { return NoopContext.INSTANCE; @@ -375,10 +476,25 @@ public void cancel(final Set> weakReferen public static class NoopContext implements Context { public static final NoopContext INSTANCE = new NoopContext(); + @Override + public DDId getTraceId() { + return DDId.ZERO; + } + + @Override + public DDId getSpanId() { + return DDId.ZERO; + } + @Override public AgentTrace getTrace() { return NoopAgentTrace.INSTANCE; } + + @Override + public Iterable> baggageItems() { + return Collections.emptyList(); + } } public static class NoopAgentTrace implements AgentTrace { From c5288e126dcea8ae99eb02c8e88b802c5bc1ec2a Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Mon, 1 Jun 2020 12:48:20 -0400 Subject: [PATCH 2/4] Remove OpenTracing dependency --- .../agent-tooling/agent-tooling.gradle | 1 - .../agent/tooling/ClassLoaderMatcher.java | 4 +-- .../trace/agent/tooling/Constants.java | 7 +---- .../jetty-perftest/jetty-perftest.gradle | 3 +- .../play-perftest/play-perftest.gradle | 2 +- dd-java-agent/dd-java-agent.gradle | 2 -- .../akka-http-10.0/akka-http-10.0.gradle | 6 ---- .../ShadowPackageRenamingTest.groovy | 30 ++++++++----------- .../jvmbootstraptest/LogManagerSetter.java | 3 +- .../datadog/trace/agent/test/SpockRunner.java | 2 -- dd-java-agent/testing/testing.gradle | 1 - dd-smoke-tests/play/play.gradle | 2 +- dd-trace-ot/dd-trace-ot.gradle | 5 +++- gradle/dependencies.gradle | 10 ------- 14 files changed, 26 insertions(+), 52 deletions(-) diff --git a/dd-java-agent/agent-tooling/agent-tooling.gradle b/dd-java-agent/agent-tooling/agent-tooling.gradle index 04c6634603f..0ff090adbc9 100644 --- a/dd-java-agent/agent-tooling/agent-tooling.gradle +++ b/dd-java-agent/agent-tooling/agent-tooling.gradle @@ -19,7 +19,6 @@ dependencies { annotationProcessor deps.autoservice implementation deps.autoservice - compile project(':dd-trace-ot') compile project(':dd-trace-core') compile project(':dd-trace-core:jfr-openjdk') diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java index 150cb6feae8..9fdf0d37688 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java @@ -1,8 +1,8 @@ package datadog.trace.agent.tooling; +import datadog.trace.api.Tracer; import datadog.trace.bootstrap.PatchLogger; import datadog.trace.bootstrap.WeakCache; -import io.opentracing.util.GlobalTracer; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.matcher.ElementMatcher; @@ -86,7 +86,7 @@ private static boolean shouldSkipClass(final ClassLoader loader) { */ private static boolean delegatesToBootstrap(final ClassLoader loader) { boolean delegates = true; - if (!loadsExpectedClass(loader, GlobalTracer.class)) { + if (!loadsExpectedClass(loader, Tracer.class)) { log.debug("loader {} failed to delegate bootstrap opentracing class", loader); delegates = false; } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Constants.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Constants.java index ee39bc5c5dd..864345ad4a9 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Constants.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Constants.java @@ -20,7 +20,6 @@ public final class Constants { "datadog.trace.bootstrap", "datadog.trace.context", "datadog.trace.instrumentation.api", - "io.opentracing" }; // This is used in IntegrationTestUtils.java @@ -37,12 +36,8 @@ public final class Constants { "com.blogspot.mydailyjava.weaklockfree", // bytebuddy "net.bytebuddy", - // OT contribs for dd trace resolver - "io.opentracing.contrib", - // jackson + // msgpack "org.msgpack", - "com.fasterxml.jackson", - "org.yaml.snakeyaml", // disruptor "com.lmax.disruptor", // okHttp diff --git a/dd-java-agent/benchmark-integration/jetty-perftest/jetty-perftest.gradle b/dd-java-agent/benchmark-integration/jetty-perftest/jetty-perftest.gradle index 59f5e8fff92..81b0351c52a 100644 --- a/dd-java-agent/benchmark-integration/jetty-perftest/jetty-perftest.gradle +++ b/dd-java-agent/benchmark-integration/jetty-perftest/jetty-perftest.gradle @@ -1,7 +1,8 @@ dependencies { compile project(':dd-trace-api') compile project(':dd-java-agent:benchmark-integration') - compile deps.opentracing + compile group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' + compile group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.1.v20170120' compile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.4.1.v20170120' diff --git a/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle b/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle index 894f2b0f29f..a1a548c0adc 100644 --- a/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle +++ b/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle @@ -22,7 +22,7 @@ dependencies { play project(':dd-trace-api') play project(':dd-java-agent:benchmark-integration') - play deps.opentracing + play group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' } repositories { diff --git a/dd-java-agent/dd-java-agent.gradle b/dd-java-agent/dd-java-agent.gradle index 90c83e0d65d..bd293fa7111 100644 --- a/dd-java-agent/dd-java-agent.gradle +++ b/dd-java-agent/dd-java-agent.gradle @@ -97,7 +97,6 @@ modifyPom { dependencies { testCompile project(':dd-java-agent:agent-bootstrap') testCompile project(':dd-trace-api') - testCompile project(':dd-trace-ot') testCompile project(':dd-trace-core') testCompile project(':utils:test-utils') @@ -106,7 +105,6 @@ dependencies { // Includes for the top level shadow jar shadowInclude project(path: ':dd-java-agent:agent-bootstrap') - shadowInclude deps.opentracing // Includes for the shared internal shadow jar sharedShadowInclude deps.shared diff --git a/dd-java-agent/instrumentation/akka-http-10.0/akka-http-10.0.gradle b/dd-java-agent/instrumentation/akka-http-10.0/akka-http-10.0.gradle index 33db693c31a..896d7a05398 100644 --- a/dd-java-agent/instrumentation/akka-http-10.0/akka-http-10.0.gradle +++ b/dd-java-agent/instrumentation/akka-http-10.0/akka-http-10.0.gradle @@ -72,12 +72,6 @@ muzzle { dependencies { main_java8CompileOnly group: 'com.typesafe.akka', name: 'akka-http_2.11', version: '10.0.0' - compile project(':dd-trace-api') - compile project(':dd-java-agent:agent-tooling') - compile deps.opentracing - compile deps.autoservice - annotationProcessor deps.autoservice - testCompile group: 'com.typesafe.akka', name: 'akka-http_2.11', version: '10.0.0' testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0' testCompile project(':dd-java-agent:instrumentation:trace-annotation') diff --git a/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy index 98c586664e8..1e8a5f93384 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy @@ -3,12 +3,8 @@ package datadog.trace.agent.integration.classloading import com.google.common.collect.MapMaker import com.google.common.reflect.ClassPath import datadog.trace.agent.test.IntegrationTestUtils -import io.opentracing.util.GlobalTracer -import spock.lang.Ignore import spock.lang.Specification -import java.lang.reflect.Field - class ShadowPackageRenamingTest extends Specification { def "agent dependencies renamed"() { setup: @@ -34,19 +30,19 @@ class ShadowPackageRenamingTest extends Specification { agentSource.getFile() != userGuava.getFile() } - @Ignore("OT 0.32 removed this field. Need to find another option.") - def "java getLogger rewritten to safe logger"() { - setup: - Field logField = GlobalTracer.getDeclaredField("LOGGER") - logField.setAccessible(true) - Object logger = logField.get(null) - - expect: - !logger.getClass().getName().startsWith("java.util.logging") - - cleanup: - logField?.setAccessible(false) - } +// @Ignore("OT 0.32 removed this field. Need to find another option.") +// def "java getLogger rewritten to safe logger"() { +// setup: +// Field logField = io.opentracing.util.GlobalTracer.getDeclaredField("LOGGER") +// logField.setAccessible(true) +// Object logger = logField.get(null) +// +// expect: +// !logger.getClass().getName().startsWith("java.util.logging") +// +// cleanup: +// logField?.setAccessible(false) +// } def "agent classes not visible"() { when: diff --git a/dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java b/dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java index a13a46e00a6..e5976ff089c 100644 --- a/dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java +++ b/dd-java-agent/src/test/java/jvmbootstraptest/LogManagerSetter.java @@ -1,5 +1,6 @@ package jvmbootstraptest; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import java.util.logging.LogManager; public class LogManagerSetter { @@ -194,7 +195,7 @@ private static boolean isProfilingStarted(final boolean wait) { private static boolean isTracerInstalled(final boolean wait) { // Wait up to 10 seconds for tracer to get installed for (int i = 0; i < 20; i++) { - if (io.opentracing.util.GlobalTracer.isRegistered()) { + if (AgentTracer.isRegistered()) { return true; } if (!wait) { diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java index 740649f03db..966d1318d26 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java @@ -38,7 +38,6 @@ public class SpockRunner extends Sputnik { "datadog.trace.bootstrap", "datadog.trace.context", "datadog.trace.instrumentation.api", - "io.opentracing" }; private static final String[] TEST_BOOTSTRAP_PREFIXES; @@ -46,7 +45,6 @@ public class SpockRunner extends Sputnik { static { ByteBuddyAgent.install(); final String[] testBS = { - "io.opentracing", "org.slf4j", "ch.qos.logback", // Tomcat's servlet classes must be on boostrap diff --git a/dd-java-agent/testing/testing.gradle b/dd-java-agent/testing/testing.gradle index 11e6b8296a6..6ab89fe6a5b 100644 --- a/dd-java-agent/testing/testing.gradle +++ b/dd-java-agent/testing/testing.gradle @@ -16,7 +16,6 @@ dependencies { compile deps.bytebuddy compile deps.bytebuddyagent compile deps.slf4j - compile deps.opentracing compile deps.spock compile deps.testLogging compile deps.guava diff --git a/dd-smoke-tests/play/play.gradle b/dd-smoke-tests/play/play.gradle index fda92842109..52342ea06d4 100644 --- a/dd-smoke-tests/play/play.gradle +++ b/dd-smoke-tests/play/play.gradle @@ -50,7 +50,7 @@ dependencies { play "com.typesafe.play:filters-helpers_$scalaVersion:$playVersion" play project(':dd-trace-api') - play deps.opentracing + play group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' testCompile project(':dd-smoke-tests') } diff --git a/dd-trace-ot/dd-trace-ot.gradle b/dd-trace-ot/dd-trace-ot.gradle index 3cd87845bf6..d818ef77b03 100644 --- a/dd-trace-ot/dd-trace-ot.gradle +++ b/dd-trace-ot/dd-trace-ot.gradle @@ -36,7 +36,10 @@ dependencies { compile project(':dd-trace-api') compile project(':dd-trace-core') - compile deps.opentracing + // OpenTracing + compile group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' + compile group: 'io.opentracing', name: 'opentracing-noop', version: '0.32.0' + compile group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' compile group: 'io.opentracing.contrib', name: 'opentracing-tracerresolver', version: '0.1.0' compile deps.slf4j diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 183e585e56d..6da9585868a 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -3,8 +3,6 @@ def spockGroovyVer = groovyVer.replaceAll(/\.\d+$/, '') ext { versions = [ - opentracing : '0.32.0', - slf4j : "1.7.30", guava : "20.0", // Last version to support Java 7 okhttp : "3.12.12", // 3.12.x is last version to support Java7) @@ -27,14 +25,6 @@ ext { ] deps = [ - // OpenTracing - opentracingApi: dependencies.create(group: 'io.opentracing', name: 'opentracing-api', version: versions.opentracing), - opentracing : [ - dependencies.create(group: 'io.opentracing', name: 'opentracing-api', version: versions.opentracing), - dependencies.create(group: 'io.opentracing', name: 'opentracing-noop', version: versions.opentracing), - dependencies.create(group: 'io.opentracing', name: 'opentracing-util', version: versions.opentracing), - ], - // General slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", guava : "com.google.guava:guava:$versions.guava", From b52ec52841b0b37b6bb76dfe663bee988b5541b9 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Thu, 28 May 2020 14:15:50 -0400 Subject: [PATCH 3/4] Add OpenTracing instrumentation for GlobalTracer --- dd-java-agent/dd-java-agent.gradle | 18 ++ .../opentracing/api-0.31/api-0.31.gradle | 18 ++ .../GlobalTracerInstrumentation.java | 73 +++++ .../opentracing31/OTPropagation.java | 40 +++ .../opentracing31/OTScopeManager.java | 88 ++++++ .../instrumentation/opentracing31/OTSpan.java | 182 +++++++++++++ .../opentracing31/OTSpanContext.java | 22 ++ .../opentracing31/OTTracer.java | 164 ++++++++++++ .../opentracing31/TypeConverter.java | 69 +++++ .../src/test/groovy/OpenTracing31Test.groovy | 250 ++++++++++++++++++ .../opentracing/api-0.32/api-0.32.gradle | 18 ++ .../GlobalTracerInstrumentation.java | 66 +++++ .../opentracing32/OTPropagation.java | 41 +++ .../opentracing32/OTScopeManager.java | 98 +++++++ .../instrumentation/opentracing32/OTSpan.java | 189 +++++++++++++ .../opentracing32/OTSpanContext.java | 32 +++ .../opentracing32/OTTracer.java | 183 +++++++++++++ .../opentracing32/TypeConverter.java | 69 +++++ .../src/test/groovy/OpenTracing32Test.groovy | 250 ++++++++++++++++++ .../opentracing/opentracing.gradle | 5 + .../opentracing/DefaultLogHandler.java | 45 ++++ .../opentracing/LogHandler.java | 44 +++ .../opentracing/OpenTracingTest.groovy | 38 +++ settings.gradle | 3 + 24 files changed, 2005 insertions(+) create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/api-0.31.gradle create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/GlobalTracerInstrumentation.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTPropagation.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTScopeManager.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpan.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpanContext.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTTracer.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/TypeConverter.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.31/src/test/groovy/OpenTracing31Test.groovy create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/GlobalTracerInstrumentation.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTPropagation.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTScopeManager.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpan.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpanContext.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTTracer.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/TypeConverter.java create mode 100644 dd-java-agent/instrumentation/opentracing/api-0.32/src/test/groovy/OpenTracing32Test.groovy create mode 100644 dd-java-agent/instrumentation/opentracing/opentracing.gradle create mode 100644 dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/DefaultLogHandler.java create mode 100644 dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/LogHandler.java create mode 100644 dd-java-agent/src/test/groovy/datadog/trace/agent/integration/opentracing/OpenTracingTest.groovy diff --git a/dd-java-agent/dd-java-agent.gradle b/dd-java-agent/dd-java-agent.gradle index bd293fa7111..75e8b14e8ac 100644 --- a/dd-java-agent/dd-java-agent.gradle +++ b/dd-java-agent/dd-java-agent.gradle @@ -1,5 +1,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import java.util.concurrent.atomic.AtomicBoolean + plugins { id "com.github.johnrengelman.shadow" version "5.2.0" } @@ -45,7 +47,22 @@ ext.generalShadowJarConfig = { } def includeShadowJar(shadowJarTask, jarname) { + def opentracingFound = new AtomicBoolean() project.processResources { + doFirst { + eachFile { + // We seem unlikely to use this name somewhere else. + if (it.path.contains("opentracing") && it.name.contains("Format\$Builtin")) { + opentracingFound.set(true) + } + } + } + doLast { + if (opentracingFound.get()) { + throw new GradleException("OpenTracing direct dependency found!") + } + } + from(zipTree(shadowJarTask.archiveFile)) { into jarname + '.isolated' rename '(^.*)\\.class$', '$1.classdata' @@ -102,6 +119,7 @@ dependencies { testCompile deps.testLogging testCompile deps.guava + testCompile group: 'io.opentracing', name: 'opentracing-util', version: '0.31.0' // Includes for the top level shadow jar shadowInclude project(path: ':dd-java-agent:agent-bootstrap') diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/api-0.31.gradle b/dd-java-agent/instrumentation/opentracing/api-0.31/api-0.31.gradle new file mode 100644 index 00000000000..17ade6aa9a7 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/api-0.31.gradle @@ -0,0 +1,18 @@ +muzzle { + pass { + module = 'opentracing-util' + group = 'io.opentracing' + versions = '[0.31.0,0.31.0]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + compile project(':dd-java-agent:instrumentation:opentracing') + + compileOnly group: 'io.opentracing', name: 'opentracing-util', version: '0.31.0' + + testCompile group: 'io.opentracing', name: 'opentracing-util', version: '0.31.0' +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/GlobalTracerInstrumentation.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/GlobalTracerInstrumentation.java new file mode 100644 index 00000000000..3b049d5462a --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/GlobalTracerInstrumentation.java @@ -0,0 +1,73 @@ +package datadog.trace.instrumentation.opentracing31; + +import static datadog.trace.agent.tooling.ClassLoaderMatcher.hasClassesNamed; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.muzzle.ReferenceCreator; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import io.opentracing.util.GlobalTracer; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * OT interface is reimplemented here rather than using dd-trace-ot as a dependency to allow muzzle + * to work correctly since it relies on the {@link ReferenceCreator#REFERENCE_CREATION_PACKAGE} + * prefix. + */ +@AutoService(Instrumenter.class) +public class GlobalTracerInstrumentation extends Instrumenter.Default { + public GlobalTracerInstrumentation() { + super("opentracing", "opentracing-globaltracer"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return not(hasClassesNamed("io.opentracing.tag.Tag")); + } + + @Override + public ElementMatcher typeMatcher() { + return named("io.opentracing.util.GlobalTracer"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".OTTracer", + packageName + ".OTTracer$OTSpanBuilder", + packageName + ".OTPropagation$TextMapInjectSetter", + packageName + ".OTPropagation$TextMapExtractGetter", + packageName + ".OTScopeManager", + packageName + ".OTScopeManager$OTScope", + packageName + ".OTScopeManager$OTTraceScope", + packageName + ".TypeConverter", + packageName + ".OTSpan", + packageName + ".OTSpanContext", + "datadog.trace.instrumentation.opentracing.LogHandler", + "datadog.trace.instrumentation.opentracing.DefaultLogHandler", + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isTypeInitializer(), GlobalTracerInstrumentation.class.getName() + "$GlobalTracerAdvice"); + } + + public static class GlobalTracerAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void registerTracer() { + if (AgentTracer.isRegistered()) { + GlobalTracer.register(new OTTracer(AgentTracer.get())); + } + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTPropagation.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTPropagation.java new file mode 100644 index 00000000000..4757627e2fd --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTPropagation.java @@ -0,0 +1,40 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; +import io.opentracing.propagation.TextMap; +import java.util.HashMap; +import java.util.Map; + +class OTPropagation { + + static class TextMapInjectSetter implements AgentPropagation.Setter { + static final TextMapInjectSetter INSTANCE = new TextMapInjectSetter(); + + @Override + public void set(final TextMap carrier, final String key, final String value) { + carrier.put(key, value); + } + } + + static class TextMapExtractGetter implements AgentPropagation.Getter { + private final Map extracted = new HashMap<>(); + + TextMapExtractGetter(final TextMap carrier) { + for (final Map.Entry entry : carrier) { + extracted.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public Iterable keys(final TextMap carrier) { + return extracted.keySet(); + } + + @Override + public String get(final TextMap carrier, final String key) { + // This is the same as the one passed into the constructor + // So using "extracted" is valid + return extracted.get(key); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTScopeManager.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTScopeManager.java new file mode 100644 index 00000000000..4032b135679 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTScopeManager.java @@ -0,0 +1,88 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.context.TraceScope; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +public class OTScopeManager implements ScopeManager { + private final TypeConverter converter; + private final AgentTracer.TracerAPI tracer; + + public OTScopeManager(final AgentTracer.TracerAPI tracer, final TypeConverter converter) { + this.tracer = tracer; + this.converter = converter; + } + + @Override + public Scope activate(final Span span, final boolean finishSpanOnClose) { + final AgentSpan agentSpan = converter.toAgentSpan(span); + final AgentScope agentScope = tracer.activateSpan(agentSpan); + + return converter.toScope(agentScope, finishSpanOnClose); + } + + @Deprecated + @Override + public Scope active() { + // WARNING... Making an assumption about finishSpanOnClose + return converter.toScope(tracer.activeScope(), false); + } + + static class OTScope implements Scope { + private final AgentScope delegate; + private final boolean finishSpanOnClose; + private final TypeConverter converter; + + OTScope( + final AgentScope delegate, final boolean finishSpanOnClose, final TypeConverter converter) { + this.delegate = delegate; + this.finishSpanOnClose = finishSpanOnClose; + this.converter = converter; + } + + @Override + public void close() { + delegate.close(); + + if (finishSpanOnClose) { + delegate.span().finish(); + } + } + + @Override + public Span span() { + return converter.toSpan(delegate.span()); + } + } + + static class OTTraceScope extends OTScope implements TraceScope { + private final TraceScope delegate; + + OTTraceScope( + final TraceScope delegate, final boolean finishSpanOnClose, final TypeConverter converter) { + // All instances of TraceScope implement agent scope (but not vice versa) + super((AgentScope) delegate, finishSpanOnClose, converter); + + this.delegate = delegate; + } + + @Override + public Continuation capture() { + return delegate.capture(); + } + + @Override + public boolean isAsyncPropagating() { + return delegate.isAsyncPropagating(); + } + + @Override + public void setAsyncPropagation(final boolean value) { + delegate.setAsyncPropagation(value); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpan.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpan.java new file mode 100644 index 00000000000..340dc8e3e63 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpan.java @@ -0,0 +1,182 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.api.interceptor.MutableSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.instrumentation.opentracing.LogHandler; +import io.opentracing.Span; +import io.opentracing.SpanContext; +import java.util.Map; + +/** + * This class should be castable to MutableSpan since that is the way we've encouraged users to + * interact with non-ot parts of our API. + */ +class OTSpan implements Span, MutableSpan { + private final AgentSpan delegate; + private final TypeConverter converter; + private final LogHandler logHandler; + + OTSpan(final AgentSpan delegate, final TypeConverter converter, final LogHandler logHandler) { + this.delegate = delegate; + this.converter = converter; + this.logHandler = logHandler; + } + + @Override + public SpanContext context() { + return converter.toSpanContext(delegate.context()); + } + + @Override + public OTSpan setTag(final String key, final String value) { + delegate.setTag(key, value); + return this; + } + + @Override + public OTSpan setTag(final String key, final boolean value) { + delegate.setTag(key, value); + return this; + } + + @Override + public OTSpan setTag(final String key, final Number value) { + delegate.setTag(key, value); + return this; + } + + @Override + public Boolean isError() { + return delegate.isError(); + } + + @Override + public MutableSpan setError(final boolean value) { + return delegate.setError(value); + } + + @Override + public MutableSpan getRootSpan() { + return delegate.getLocalRootSpan(); + } + + @Override + public MutableSpan getLocalRootSpan() { + return delegate.getLocalRootSpan(); + } + + @Override + public Span log(final Map fields) { + logHandler.log(fields, delegate); + return this; + } + + @Override + public Span log(final long timestampMicroseconds, final Map fields) { + logHandler.log(timestampMicroseconds, fields, delegate); + return this; + } + + @Override + public Span log(final String event) { + logHandler.log(event, delegate); + return this; + } + + @Override + public Span log(final long timestampMicroseconds, final String event) { + logHandler.log(timestampMicroseconds, event, delegate); + return this; + } + + @Override + public Span setBaggageItem(final String key, final String value) { + delegate.setBaggageItem(key, value); + return this; + } + + @Override + public String getBaggageItem(final String key) { + return delegate.getBaggageItem(key); + } + + @Override + public long getStartTime() { + return delegate.getStartTime(); + } + + @Override + public long getDurationNano() { + return delegate.getDurationNano(); + } + + @Override + public String getOperationName() { + return delegate.getOperationName(); + } + + @Override + public OTSpan setOperationName(final String operationName) { + delegate.setOperationName(operationName); + return this; + } + + @Override + public String getServiceName() { + return delegate.getServiceName(); + } + + @Override + public MutableSpan setServiceName(final String serviceName) { + return delegate.setServiceName(serviceName); + } + + @Override + public String getResourceName() { + return delegate.getResourceName(); + } + + @Override + public MutableSpan setResourceName(final String resourceName) { + return delegate.setResourceName(resourceName); + } + + @Override + public Integer getSamplingPriority() { + return delegate.getSamplingPriority(); + } + + @Override + public MutableSpan setSamplingPriority(final int newPriority) { + return delegate.setSamplingPriority(newPriority); + } + + @Override + public String getSpanType() { + return delegate.getSpanType(); + } + + @Override + public MutableSpan setSpanType(final String type) { + return delegate.setSpanType(type); + } + + @Override + public Map getTags() { + return delegate.getTags(); + } + + @Override + public void finish() { + delegate.finish(); + } + + @Override + public void finish(final long finishMicros) { + delegate.finish(finishMicros); + } + + public AgentSpan getDelegate() { + return delegate; + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpanContext.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpanContext.java new file mode 100644 index 00000000000..23622bfed57 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTSpanContext.java @@ -0,0 +1,22 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import io.opentracing.SpanContext; +import java.util.Map; + +class OTSpanContext implements SpanContext { + private final AgentSpan.Context delegate; + + OTSpanContext(final AgentSpan.Context delegate) { + this.delegate = delegate; + } + + @Override + public Iterable> baggageItems() { + return delegate.baggageItems(); + } + + AgentSpan.Context getDelegate() { + return delegate; + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTTracer.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTTracer.java new file mode 100644 index 00000000000..c9fdfe087cb --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/OTTracer.java @@ -0,0 +1,164 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.core.DDSpanContext; +import datadog.trace.core.propagation.ExtractedContext; +import datadog.trace.instrumentation.opentracing.DefaultLogHandler; +import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; +import io.opentracing.SpanContext; +import io.opentracing.Tracer; +import io.opentracing.propagation.Format; +import io.opentracing.propagation.TextMap; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OTTracer implements Tracer { + + private final TypeConverter converter = new TypeConverter(new DefaultLogHandler()); + private final AgentTracer.TracerAPI tracer; + private final ScopeManager scopeManager; + + public OTTracer(final AgentTracer.TracerAPI tracer) { + this.tracer = tracer; + scopeManager = new OTScopeManager(tracer, converter); + } + + @Override + public ScopeManager scopeManager() { + return scopeManager; + } + + @Override + public Span activeSpan() { + return converter.toSpan(AgentTracer.activeSpan()); + } + + @Override + public SpanBuilder buildSpan(final String operationName) { + return new OTSpanBuilder(tracer.buildSpan(operationName), converter); + } + + @Override + public void inject(final SpanContext spanContext, final Format format, final C carrier) { + if (carrier instanceof TextMap) { + final AgentSpan.Context context = converter.toContext(spanContext); + + tracer.inject(context, (TextMap) carrier, OTPropagation.TextMapInjectSetter.INSTANCE); + } else { + log.debug("Unsupported format for propagation - {}", format.getClass().getName()); + } + } + + @Override + public SpanContext extract(final Format format, final C carrier) { + if (carrier instanceof TextMap) { + final AgentSpan.Context tagContext = + tracer.extract( + (TextMap) carrier, new OTPropagation.TextMapExtractGetter((TextMap) carrier)); + + return converter.toSpanContext(tagContext); + } else { + log.debug("Unsupported format for propagation - {}", format.getClass().getName()); + return null; + } + } + + public class OTSpanBuilder implements Tracer.SpanBuilder { + private final AgentTracer.SpanBuilder delegate; + private final TypeConverter converter; + + public OTSpanBuilder(final AgentTracer.SpanBuilder delegate, final TypeConverter converter) { + this.delegate = delegate; + this.converter = converter; + } + + @Override + public Tracer.SpanBuilder asChildOf(final SpanContext parent) { + delegate.asChildOf(converter.toContext(parent)); + return this; + } + + @Override + public Tracer.SpanBuilder asChildOf(final Span parent) { + if (parent != null) { + delegate.asChildOf(converter.toAgentSpan(parent).context()); + } + return this; + } + + @Override + public Tracer.SpanBuilder addReference( + final String referenceType, final SpanContext referencedContext) { + if (referencedContext == null) { + return this; + } + + final AgentSpan.Context context = converter.toContext(referencedContext); + if (!(context instanceof ExtractedContext) && !(context instanceof DDSpanContext)) { + log.debug( + "Expected to have a DDSpanContext or ExtractedContext but got " + + context.getClass().getName()); + return this; + } + + if (References.CHILD_OF.equals(referenceType) + || References.FOLLOWS_FROM.equals(referenceType)) { + delegate.asChildOf(context); + } else { + log.debug("Only support reference type of CHILD_OF and FOLLOWS_FROM"); + } + + return this; + } + + @Override + public OTSpanBuilder ignoreActiveSpan() { + delegate.ignoreActiveSpan(); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final String value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final boolean value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final Number value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withStartTimestamp(final long microseconds) { + delegate.withStartTimestamp(microseconds); + return this; + } + + @Override + public Span startManual() { + return start(); + } + + @Override + public Span start() { + final AgentSpan agentSpan = delegate.start(); + return converter.toSpan(agentSpan); + } + + @Override + public Scope startActive(final boolean finishSpanOnClose) { + return converter.toScope(tracer.activateSpan(delegate.start()), finishSpanOnClose); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/TypeConverter.java b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/TypeConverter.java new file mode 100644 index 00000000000..e4026015a0f --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/main/java/datadog/trace/instrumentation/opentracing31/TypeConverter.java @@ -0,0 +1,69 @@ +package datadog.trace.instrumentation.opentracing31; + +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.context.TraceScope; +import datadog.trace.instrumentation.opentracing.LogHandler; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.SpanContext; + +// Centralized place to do conversions +public class TypeConverter { + // TODO maybe add caching to reduce new objects being created + + private final LogHandler logHandler; + + public TypeConverter(final LogHandler logHandler) { + this.logHandler = logHandler; + } + + public AgentSpan toAgentSpan(final Span span) { + if (span == null) { + return null; + } else if (span instanceof OTSpan) { + return ((OTSpan) span).getDelegate(); + } else { + // NOOP Span, otherwise arbitrary spans aren't supported. + return AgentTracer.NoopAgentSpan.INSTANCE; + } + } + + public Span toSpan(final AgentSpan agentSpan) { + if (agentSpan == null) { + return null; + } + return new OTSpan(agentSpan, this, logHandler); + } + + // FIXME [API] Need to use the runtime type not compile-time type so "Object" is used + // That fact that some methods return AgentScope and other TraceScope even though its the same + // underlying object needs to be cleaned up + public Scope toScope(final Object scope, final boolean finishSpanOnClose) { + if (scope == null) { + return null; + } else if (scope instanceof TraceScope) { + return new OTScopeManager.OTTraceScope((TraceScope) scope, finishSpanOnClose, this); + } else { + return new OTScopeManager.OTScope((AgentScope) scope, finishSpanOnClose, this); + } + } + + public SpanContext toSpanContext(final AgentSpan.Context context) { + if (context == null) { + return null; + } + return new OTSpanContext(context); + } + + public AgentSpan.Context toContext(final SpanContext spanContext) { + if (spanContext == null) { + return null; + } else if (spanContext instanceof OTSpanContext) { + return ((OTSpanContext) spanContext).getDelegate(); + } else { + return AgentTracer.NoopContext.INSTANCE; + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.31/src/test/groovy/OpenTracing31Test.groovy b/dd-java-agent/instrumentation/opentracing/api-0.31/src/test/groovy/OpenTracing31Test.groovy new file mode 100644 index 00000000000..5cc79dccb0f --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.31/src/test/groovy/OpenTracing31Test.groovy @@ -0,0 +1,250 @@ +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.DDTags +import datadog.trace.api.interceptor.MutableSpan +import datadog.trace.context.TraceScope +import datadog.trace.core.DDSpan +import io.opentracing.log.Fields +import io.opentracing.noop.NoopSpan +import io.opentracing.propagation.Format +import io.opentracing.propagation.TextMap +import io.opentracing.util.GlobalTracer +import spock.lang.Subject + +class OpenTracing31Test extends AgentTestRunner { + + @Subject + def tracer = GlobalTracer.get() + + def "test #method"() { + setup: + def builder = tracer.buildSpan("some name") + if (tagBuilder) { + builder.withTag(DDTags.RESOURCE_NAME, "some resource") + .withTag("string", "a") + .withTag("number", 1) + .withTag("boolean", true) + } + def result = builder.start() + if (tagSpan) { + result.setTag(DDTags.RESOURCE_NAME, "other resource") + .setTag("string", "b") + .setTag("number", 2) + .setTag("boolean", false) + } + if (exception) { + result.log([(Fields.ERROR_OBJECT): exception]) + } + + expect: + result instanceof MutableSpan + (result as MutableSpan).localRootSpan == result.delegate + (result as MutableSpan).isError() == (exception != null) + tracer.activeSpan() == null + result.context().baggageItems().isEmpty() + + when: + result.setBaggageItem("test", "baggage") + + then: + result.getBaggageItem("test") == "baggage" + result.context().baggageItems() == ["test": "baggage"].entrySet() + + when: + result.finish() + + then: + assertTraces(1) { + trace(0, 1) { + span(0) { + parent() + serviceName "unnamed-java-app" + operationName "some name" + if (tagSpan) { + resourceName "other resource" + } else if (tagBuilder) { + resourceName "some resource" + } else { + resourceName "some name" + } + errored exception != null + tags { + if (tagSpan) { + "string" "b" + "number" 2 + "boolean" false + } else if (tagBuilder) { + "string" "a" + "number" 1 + "boolean" true + } + if (exception) { + errorTags(exception.class) + } + defaultTags() + } + metrics { + defaultMetrics() + } + } + } + } + + where: + method | tagBuilder | tagSpan | exception + "start" | true | false | null + "startManual" | true | true | new Exception() + "startManual" | false | false | new Exception() + "start" | false | true | null + } + + def "test startActive"() { + setup: + def scope = tracer.buildSpan("some name").startActive(finishSpan) + + expect: + scope instanceof TraceScope + tracer.activeSpan().delegate == scope.span().delegate + + when: + scope.close() + + then: + (scope.span().delegate as DDSpan).isFinished() == finishSpan + + where: + finishSpan << [true, false] + } + + def "test scopemanager"() { + setup: + def span = tracer.buildSpan("some name").start() + def scope = tracer.scopeManager().activate(span, finishSpan) + + expect: + span instanceof MutableSpan + scope instanceof TraceScope + !(scope as TraceScope).isAsyncPropagating() + (scope as TraceScope).capture() == null + (tracer.scopeManager().active().span().delegate == span.delegate) + + when: + (scope as TraceScope).setAsyncPropagation(true) + def continuation = (scope as TraceScope).capture() + continuation.cancel() + + then: + (scope as TraceScope).isAsyncPropagating() + continuation instanceof TraceScope.Continuation + + when: "attempting to close the span this way doesn't work because we lost the 'finishSpan' reference" + tracer.scopeManager().active().close() + + then: + !(span.delegate as DDSpan).isFinished() + + when: + scope.close() + + then: + (span.delegate as DDSpan).isFinished() == finishSpan + + where: + finishSpan | _ + true | _ + false | _ + } + + def "test scopemanager with non OTSpan"() { + setup: + def span = NoopSpan.INSTANCE + def scope = tracer.scopeManager().activate(span, true) + + expect: + !(span instanceof MutableSpan) + scope instanceof TraceScope + + and: "non OTSpans aren't supported and get converted to NoopAgentSpan" + tracer.scopeManager().active().span() != span + + when: + scope.close() + scope.span().finish() + + then: + assertTraces(0) {} + } + + def "test continuation"() { + setup: + def span = tracer.buildSpan("some name").start() + TraceScope scope = tracer.scopeManager().activate(span, false) + scope.setAsyncPropagation(true) + + expect: + tracer.activeSpan().delegate == span.delegate + + when: + def continuation = scope.capture() + + then: + continuation instanceof TraceScope.Continuation + + when: + scope.close() + + then: + tracer.activeSpan() == null + + when: + scope = continuation.activate() + + then: + tracer.activeSpan().delegate == span.delegate + + cleanup: + scope.close() + } + + def "test inject extract"() { + setup: + def context = tracer.buildSpan("some name").start().context() + def textMap = [:] + def adapter = new TextMapAdapter(textMap) + + when: + tracer.inject(context, Format.Builtin.TEXT_MAP, adapter) + + then: + textMap == [ + "x-datadog-trace-id" : "$context.delegate.traceId", + "x-datadog-parent-id" : "$context.delegate.spanId", + "x-datadog-sampling-priority": "$context.delegate.samplingPriority", + ] + + when: + def extract = tracer.extract(Format.Builtin.TEXT_MAP, adapter) + + then: + extract.delegate.traceId == context.delegate.traceId + extract.delegate.spanId == context.delegate.spanId + extract.delegate.samplingPriority == context.delegate.samplingPriority + } + + static class TextMapAdapter implements TextMap { + private final Map map + + TextMapAdapter(Map map) { + this.map = map + } + + @Override + Iterator> iterator() { + return map.entrySet().iterator() + } + + @Override + void put(String key, String value) { + map.put(key, value) + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle b/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle new file mode 100644 index 00000000000..7e3997d7626 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle @@ -0,0 +1,18 @@ +muzzle { + pass { + module = 'opentracing-util' + group = 'io.opentracing' + versions = '[0.32.0,]' + assertInverse = true + } +} + +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + compile project(':dd-java-agent:instrumentation:opentracing') + + compileOnly group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' + + testCompile group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/GlobalTracerInstrumentation.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/GlobalTracerInstrumentation.java new file mode 100644 index 00000000000..3614c8645c6 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/GlobalTracerInstrumentation.java @@ -0,0 +1,66 @@ +package datadog.trace.instrumentation.opentracing32; + +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.muzzle.ReferenceCreator; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import io.opentracing.util.GlobalTracer; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * OT interface is reimplemented here rather than using dd-trace-ot as a dependency to allow muzzle + * to work correctly since it relies on the {@link ReferenceCreator#REFERENCE_CREATION_PACKAGE} + * prefix. + */ +@AutoService(Instrumenter.class) +public class GlobalTracerInstrumentation extends Instrumenter.Default { + public GlobalTracerInstrumentation() { + super("opentracing", "opentracing-globaltracer"); + } + + @Override + public ElementMatcher typeMatcher() { + return named("io.opentracing.util.GlobalTracer"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".OTTracer", + packageName + ".OTTracer$OTSpanBuilder", + packageName + ".OTPropagation$TextMapInjectSetter", + packageName + ".OTPropagation$TextMapExtractGetter", + packageName + ".OTScopeManager", + packageName + ".OTScopeManager$OTScope", + packageName + ".OTScopeManager$OTTraceScope", + packageName + ".TypeConverter", + packageName + ".OTSpan", + packageName + ".OTSpanContext", + "datadog.trace.instrumentation.opentracing.LogHandler", + "datadog.trace.instrumentation.opentracing.DefaultLogHandler", + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isTypeInitializer(), GlobalTracerInstrumentation.class.getName() + "$GlobalTracerAdvice"); + } + + public static class GlobalTracerAdvice { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void registerTracer() { + if (AgentTracer.isRegistered()) { + GlobalTracer.registerIfAbsent(new OTTracer(AgentTracer.get())); + } + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTPropagation.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTPropagation.java new file mode 100644 index 00000000000..b1536247327 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTPropagation.java @@ -0,0 +1,41 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; +import io.opentracing.propagation.TextMapExtract; +import io.opentracing.propagation.TextMapInject; +import java.util.HashMap; +import java.util.Map; + +class OTPropagation { + + static class TextMapInjectSetter implements AgentPropagation.Setter { + static final TextMapInjectSetter INSTANCE = new TextMapInjectSetter(); + + @Override + public void set(final TextMapInject carrier, final String key, final String value) { + carrier.put(key, value); + } + } + + static class TextMapExtractGetter implements AgentPropagation.Getter { + private final Map extracted = new HashMap<>(); + + TextMapExtractGetter(final TextMapExtract carrier) { + for (final Map.Entry entry : carrier) { + extracted.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public Iterable keys(final TextMapExtract carrier) { + return extracted.keySet(); + } + + @Override + public String get(final TextMapExtract carrier, final String key) { + // This is the same as the one passed into the constructor + // So using "extracted" is valid + return extracted.get(key); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTScopeManager.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTScopeManager.java new file mode 100644 index 00000000000..7576dc7ad9c --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTScopeManager.java @@ -0,0 +1,98 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.context.TraceScope; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; + +public class OTScopeManager implements ScopeManager { + private final TypeConverter converter; + private final AgentTracer.TracerAPI tracer; + + public OTScopeManager(final AgentTracer.TracerAPI tracer, final TypeConverter converter) { + this.tracer = tracer; + this.converter = converter; + } + + @Override + public Scope activate(final Span span) { + return activate(span, false); + } + + @Override + public Scope activate(final Span span, final boolean finishSpanOnClose) { + final AgentSpan agentSpan = converter.toAgentSpan(span); + final AgentScope agentScope = tracer.activateSpan(agentSpan); + + return converter.toScope(agentScope, finishSpanOnClose); + } + + @Deprecated + @Override + public Scope active() { + // WARNING... Making an assumption about finishSpanOnClose + return converter.toScope(tracer.activeScope(), false); + } + + @Override + public Span activeSpan() { + return converter.toSpan(tracer.activeSpan()); + } + + static class OTScope implements Scope { + private final AgentScope delegate; + private final boolean finishSpanOnClose; + private final TypeConverter converter; + + OTScope( + final AgentScope delegate, final boolean finishSpanOnClose, final TypeConverter converter) { + this.delegate = delegate; + this.finishSpanOnClose = finishSpanOnClose; + this.converter = converter; + } + + @Override + public void close() { + delegate.close(); + + if (finishSpanOnClose) { + delegate.span().finish(); + } + } + + @Override + public Span span() { + return converter.toSpan(delegate.span()); + } + } + + static class OTTraceScope extends OTScope implements TraceScope { + private final TraceScope delegate; + + OTTraceScope( + final TraceScope delegate, final boolean finishSpanOnClose, final TypeConverter converter) { + // All instances of TraceScope implement agent scope (but not vice versa) + super((AgentScope) delegate, finishSpanOnClose, converter); + + this.delegate = delegate; + } + + @Override + public Continuation capture() { + return delegate.capture(); + } + + @Override + public boolean isAsyncPropagating() { + return delegate.isAsyncPropagating(); + } + + @Override + public void setAsyncPropagation(final boolean value) { + delegate.setAsyncPropagation(value); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpan.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpan.java new file mode 100644 index 00000000000..04f704e198d --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpan.java @@ -0,0 +1,189 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.api.interceptor.MutableSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.instrumentation.opentracing.LogHandler; +import io.opentracing.Span; +import io.opentracing.SpanContext; +import io.opentracing.tag.Tag; +import java.util.Map; + +/** + * This class should be castable to MutableSpan since that is the way we've encouraged users to + * interact with non-ot parts of our API. + */ +class OTSpan implements Span, MutableSpan { + private final AgentSpan delegate; + private final TypeConverter converter; + private final LogHandler logHandler; + + OTSpan(final AgentSpan delegate, final TypeConverter converter, final LogHandler logHandler) { + this.delegate = delegate; + this.converter = converter; + this.logHandler = logHandler; + } + + @Override + public SpanContext context() { + return converter.toSpanContext(delegate.context()); + } + + @Override + public OTSpan setTag(final String key, final String value) { + delegate.setTag(key, value); + return this; + } + + @Override + public OTSpan setTag(final String key, final boolean value) { + delegate.setTag(key, value); + return this; + } + + @Override + public OTSpan setTag(final String key, final Number value) { + delegate.setTag(key, value); + return this; + } + + @Override + public Boolean isError() { + return delegate.isError(); + } + + @Override + public MutableSpan setError(final boolean value) { + return delegate.setError(value); + } + + @Override + public MutableSpan getRootSpan() { + return delegate.getLocalRootSpan(); + } + + @Override + public MutableSpan getLocalRootSpan() { + return delegate.getLocalRootSpan(); + } + + @Override + public Span setTag(final Tag tag, final T value) { + delegate.setTag(tag.getKey(), value); + return this; + } + + @Override + public Span log(final Map fields) { + logHandler.log(fields, delegate); + return this; + } + + @Override + public Span log(final long timestampMicroseconds, final Map fields) { + logHandler.log(timestampMicroseconds, fields, delegate); + return this; + } + + @Override + public Span log(final String event) { + logHandler.log(event, delegate); + return this; + } + + @Override + public Span log(final long timestampMicroseconds, final String event) { + logHandler.log(timestampMicroseconds, event, delegate); + return this; + } + + @Override + public Span setBaggageItem(final String key, final String value) { + delegate.setBaggageItem(key, value); + return this; + } + + @Override + public String getBaggageItem(final String key) { + return delegate.getBaggageItem(key); + } + + @Override + public long getStartTime() { + return delegate.getStartTime(); + } + + @Override + public long getDurationNano() { + return delegate.getDurationNano(); + } + + @Override + public String getOperationName() { + return delegate.getOperationName(); + } + + @Override + public OTSpan setOperationName(final String operationName) { + delegate.setOperationName(operationName); + return this; + } + + @Override + public String getServiceName() { + return delegate.getServiceName(); + } + + @Override + public MutableSpan setServiceName(final String serviceName) { + return delegate.setServiceName(serviceName); + } + + @Override + public String getResourceName() { + return delegate.getResourceName(); + } + + @Override + public MutableSpan setResourceName(final String resourceName) { + return delegate.setResourceName(resourceName); + } + + @Override + public Integer getSamplingPriority() { + return delegate.getSamplingPriority(); + } + + @Override + public MutableSpan setSamplingPriority(final int newPriority) { + return delegate.setSamplingPriority(newPriority); + } + + @Override + public String getSpanType() { + return delegate.getSpanType(); + } + + @Override + public MutableSpan setSpanType(final String type) { + return delegate.setSpanType(type); + } + + @Override + public Map getTags() { + return delegate.getTags(); + } + + @Override + public void finish() { + delegate.finish(); + } + + @Override + public void finish(final long finishMicros) { + delegate.finish(finishMicros); + } + + public AgentSpan getDelegate() { + return delegate; + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpanContext.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpanContext.java new file mode 100644 index 00000000000..cf3be701f9a --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTSpanContext.java @@ -0,0 +1,32 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import io.opentracing.SpanContext; +import java.util.Map; + +class OTSpanContext implements SpanContext { + private final AgentSpan.Context delegate; + + OTSpanContext(final AgentSpan.Context delegate) { + this.delegate = delegate; + } + + @Override + public String toTraceId() { + return delegate.getTraceId().toString(); + } + + @Override + public String toSpanId() { + return delegate.getSpanId().toString(); + } + + @Override + public Iterable> baggageItems() { + return delegate.baggageItems(); + } + + AgentSpan.Context getDelegate() { + return delegate; + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTTracer.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTTracer.java new file mode 100644 index 00000000000..73527973a61 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/OTTracer.java @@ -0,0 +1,183 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.core.DDSpanContext; +import datadog.trace.core.propagation.ExtractedContext; +import datadog.trace.instrumentation.opentracing.DefaultLogHandler; +import io.opentracing.References; +import io.opentracing.Scope; +import io.opentracing.ScopeManager; +import io.opentracing.Span; +import io.opentracing.SpanContext; +import io.opentracing.Tracer; +import io.opentracing.propagation.Format; +import io.opentracing.propagation.TextMapExtract; +import io.opentracing.propagation.TextMapInject; +import io.opentracing.tag.Tag; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OTTracer implements Tracer { + + private final TypeConverter converter = new TypeConverter(new DefaultLogHandler()); + private final AgentTracer.TracerAPI tracer; + private final ScopeManager scopeManager; + + public OTTracer(final AgentTracer.TracerAPI tracer) { + this.tracer = tracer; + scopeManager = new OTScopeManager(tracer, converter); + } + + @Override + public ScopeManager scopeManager() { + return scopeManager; + } + + @Override + public Span activeSpan() { + return converter.toSpan(AgentTracer.activeSpan()); + } + + @Override + public Scope activateSpan(final Span span) { + return converter.toScope(tracer.activateSpan(converter.toAgentSpan(span)), false); + } + + @Override + public SpanBuilder buildSpan(final String operationName) { + return new OTSpanBuilder(tracer.buildSpan(operationName), converter); + } + + @Override + public void inject(final SpanContext spanContext, final Format format, final C carrier) { + if (carrier instanceof TextMapInject) { + final AgentSpan.Context context = converter.toContext(spanContext); + + tracer.inject(context, (TextMapInject) carrier, OTPropagation.TextMapInjectSetter.INSTANCE); + } else { + log.debug("Unsupported format for propagation - {}", format.getClass().getName()); + } + } + + @Override + public SpanContext extract(final Format format, final C carrier) { + if (carrier instanceof TextMapExtract) { + final AgentSpan.Context tagContext = + tracer.extract( + (TextMapExtract) carrier, + new OTPropagation.TextMapExtractGetter((TextMapExtract) carrier)); + + return converter.toSpanContext(tagContext); + } else { + log.debug("Unsupported format for propagation - {}", format.getClass().getName()); + return null; + } + } + + @Override + public void close() { + tracer.close(); + } + + public class OTSpanBuilder implements Tracer.SpanBuilder { + private final AgentTracer.SpanBuilder delegate; + private final TypeConverter converter; + + public OTSpanBuilder(final AgentTracer.SpanBuilder delegate, final TypeConverter converter) { + this.delegate = delegate; + this.converter = converter; + } + + @Override + public Tracer.SpanBuilder asChildOf(final SpanContext parent) { + delegate.asChildOf(converter.toContext(parent)); + return this; + } + + @Override + public Tracer.SpanBuilder asChildOf(final Span parent) { + if (parent != null) { + delegate.asChildOf(converter.toAgentSpan(parent).context()); + } + return this; + } + + @Override + public Tracer.SpanBuilder addReference( + final String referenceType, final SpanContext referencedContext) { + if (referencedContext == null) { + return this; + } + + final AgentSpan.Context context = converter.toContext(referencedContext); + if (!(context instanceof ExtractedContext) && !(context instanceof DDSpanContext)) { + log.debug( + "Expected to have a DDSpanContext or ExtractedContext but got " + + context.getClass().getName()); + return this; + } + + if (References.CHILD_OF.equals(referenceType) + || References.FOLLOWS_FROM.equals(referenceType)) { + delegate.asChildOf(context); + } else { + log.debug("Only support reference type of CHILD_OF and FOLLOWS_FROM"); + } + + return this; + } + + @Override + public OTSpanBuilder ignoreActiveSpan() { + delegate.ignoreActiveSpan(); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final String value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final boolean value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withTag(final String key, final Number value) { + delegate.withTag(key, value); + return this; + } + + @Override + public OTSpanBuilder withTag(final Tag tag, final T value) { + delegate.withTag(tag.getKey(), value); + return this; + } + + @Override + public OTSpanBuilder withStartTimestamp(final long microseconds) { + delegate.withStartTimestamp(microseconds); + return this; + } + + @Override + public Span startManual() { + return start(); + } + + @Override + public Span start() { + final AgentSpan agentSpan = delegate.start(); + return converter.toSpan(agentSpan); + } + + @Override + public Scope startActive(final boolean finishSpanOnClose) { + return converter.toScope(tracer.activateSpan(delegate.start()), finishSpanOnClose); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/TypeConverter.java b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/TypeConverter.java new file mode 100644 index 00000000000..8782eeae116 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/main/java/datadog/trace/instrumentation/opentracing32/TypeConverter.java @@ -0,0 +1,69 @@ +package datadog.trace.instrumentation.opentracing32; + +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.context.TraceScope; +import datadog.trace.instrumentation.opentracing.LogHandler; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.SpanContext; + +// Centralized place to do conversions +public class TypeConverter { + // TODO maybe add caching to reduce new objects being created + + private final LogHandler logHandler; + + public TypeConverter(final LogHandler logHandler) { + this.logHandler = logHandler; + } + + public AgentSpan toAgentSpan(final Span span) { + if (span == null) { + return null; + } else if (span instanceof OTSpan) { + return ((OTSpan) span).getDelegate(); + } else { + // NOOP Span, otherwise arbitrary spans aren't supported. + return AgentTracer.NoopAgentSpan.INSTANCE; + } + } + + public Span toSpan(final AgentSpan agentSpan) { + if (agentSpan == null) { + return null; + } + return new OTSpan(agentSpan, this, logHandler); + } + + // FIXME [API] Need to use the runtime type not compile-time type so "Object" is used + // That fact that some methods return AgentScope and other TraceScope even though its the same + // underlying object needs to be cleaned up + public Scope toScope(final Object scope, final boolean finishSpanOnClose) { + if (scope == null) { + return null; + } else if (scope instanceof TraceScope) { + return new OTScopeManager.OTTraceScope((TraceScope) scope, finishSpanOnClose, this); + } else { + return new OTScopeManager.OTScope((AgentScope) scope, finishSpanOnClose, this); + } + } + + public SpanContext toSpanContext(final AgentSpan.Context context) { + if (context == null) { + return null; + } + return new OTSpanContext(context); + } + + public AgentSpan.Context toContext(final SpanContext spanContext) { + if (spanContext == null) { + return null; + } else if (spanContext instanceof OTSpanContext) { + return ((OTSpanContext) spanContext).getDelegate(); + } else { + return AgentTracer.NoopContext.INSTANCE; + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/src/test/groovy/OpenTracing32Test.groovy b/dd-java-agent/instrumentation/opentracing/api-0.32/src/test/groovy/OpenTracing32Test.groovy new file mode 100644 index 00000000000..24f4c19f7f2 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/src/test/groovy/OpenTracing32Test.groovy @@ -0,0 +1,250 @@ +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.api.DDTags +import datadog.trace.api.interceptor.MutableSpan +import datadog.trace.context.TraceScope +import datadog.trace.core.DDSpan +import io.opentracing.log.Fields +import io.opentracing.noop.NoopSpan +import io.opentracing.propagation.Format +import io.opentracing.propagation.TextMap +import io.opentracing.util.GlobalTracer +import spock.lang.Subject + +class OpenTracing32Test extends AgentTestRunner { + + @Subject + def tracer = GlobalTracer.get() + + def "test #method"() { + setup: + def builder = tracer.buildSpan("some name") + if (tagBuilder) { + builder.withTag(DDTags.RESOURCE_NAME, "some resource") + .withTag("string", "a") + .withTag("number", 1) + .withTag("boolean", true) + } + def result = builder."$method"() + if (tagSpan) { + result.setTag(DDTags.RESOURCE_NAME, "other resource") + .setTag("string", "b") + .setTag("number", 2) + .setTag("boolean", false) + } + if (exception) { + result.log([(Fields.ERROR_OBJECT): exception]) + } + + expect: + result instanceof MutableSpan + (result as MutableSpan).localRootSpan == result.delegate + (result as MutableSpan).isError() == (exception != null) + tracer.activeSpan() == null + result.context().baggageItems().isEmpty() + + when: + result.setBaggageItem("test", "baggage") + + then: + result.getBaggageItem("test") == "baggage" + result.context().baggageItems() == ["test": "baggage"].entrySet() + + when: + result.finish() + + then: + assertTraces(1) { + trace(0, 1) { + span(0) { + parent() + serviceName "unnamed-java-app" + operationName "some name" + if (tagSpan) { + resourceName "other resource" + } else if (tagBuilder) { + resourceName "some resource" + } else { + resourceName "some name" + } + errored exception != null + tags { + if (tagSpan) { + "string" "b" + "number" 2 + "boolean" false + } else if (tagBuilder) { + "string" "a" + "number" 1 + "boolean" true + } + if (exception) { + errorTags(exception.class) + } + defaultTags() + } + metrics { + defaultMetrics() + } + } + } + } + + where: + method | tagBuilder | tagSpan | exception + "start" | true | false | null + "startManual" | true | true | new Exception() + "startManual" | false | false | new Exception() + "start" | false | true | null + } + + def "test startActive"() { + setup: + def scope = tracer.buildSpan("some name").startActive(finishSpan) + + expect: + scope instanceof TraceScope + tracer.activeSpan().delegate == scope.span().delegate + + when: + scope.close() + + then: + (scope.span().delegate as DDSpan).isFinished() == finishSpan + + where: + finishSpan << [true, false] + } + + def "test scopemanager"() { + setup: + def span = tracer.buildSpan("some name").start() + def scope = tracer.scopeManager().activate(span, finishSpan) + + expect: + span instanceof MutableSpan + scope instanceof TraceScope + !(scope as TraceScope).isAsyncPropagating() + (scope as TraceScope).capture() == null + (tracer.scopeManager().active().span().delegate == span.delegate) + + when: + (scope as TraceScope).setAsyncPropagation(true) + def continuation = (scope as TraceScope).capture() + continuation.cancel() + + then: + (scope as TraceScope).isAsyncPropagating() + continuation instanceof TraceScope.Continuation + + when: "attempting to close the span this way doesn't work because we lost the 'finishSpan' reference" + tracer.scopeManager().active().close() + + then: + !(span.delegate as DDSpan).isFinished() + + when: + scope.close() + + then: + (span.delegate as DDSpan).isFinished() == finishSpan + + where: + finishSpan | _ + true | _ + false | _ + } + + def "test scopemanager with non OTSpan"() { + setup: + def span = NoopSpan.INSTANCE + def scope = tracer.scopeManager().activate(span, true) + + expect: + !(span instanceof MutableSpan) + scope instanceof TraceScope + + and: "non OTSpans aren't supported and get converted to NoopAgentSpan" + tracer.scopeManager().active().span() != span + + when: + scope.close() + scope.span().finish() + + then: + assertTraces(0) {} + } + + def "test continuation"() { + setup: + def span = tracer.buildSpan("some name").start() + TraceScope scope = tracer.scopeManager().activate(span, false) + scope.setAsyncPropagation(true) + + expect: + tracer.activeSpan().delegate == span.delegate + + when: + def continuation = scope.capture() + + then: + continuation instanceof TraceScope.Continuation + + when: + scope.close() + + then: + tracer.activeSpan() == null + + when: + scope = continuation.activate() + + then: + tracer.activeSpan().delegate == span.delegate + + cleanup: + scope.close() + } + + def "test inject extract"() { + setup: + def context = tracer.buildSpan("some name").start().context() + def textMap = [:] + def adapter = new TextMapAdapter(textMap) + + when: + tracer.inject(context, Format.Builtin.TEXT_MAP, adapter) + + then: + textMap == [ + "x-datadog-trace-id" : "$context.delegate.traceId", + "x-datadog-parent-id" : "$context.delegate.spanId", + "x-datadog-sampling-priority": "$context.delegate.samplingPriority", + ] + + when: + def extract = tracer.extract(Format.Builtin.TEXT_MAP, adapter) + + then: + extract.delegate.traceId == context.delegate.traceId + extract.delegate.spanId == context.delegate.spanId + extract.delegate.samplingPriority == context.delegate.samplingPriority + } + + static class TextMapAdapter implements TextMap { + private final Map map + + TextMapAdapter(Map map) { + this.map = map + } + + @Override + Iterator> iterator() { + return map.entrySet().iterator() + } + + @Override + void put(String key, String value) { + map.put(key, value) + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/opentracing.gradle b/dd-java-agent/instrumentation/opentracing/opentracing.gradle new file mode 100644 index 00000000000..8f7cad53ea7 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/opentracing.gradle @@ -0,0 +1,5 @@ +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + compileOnly group: 'io.opentracing', name: 'opentracing-util', version: '0.31.0' +} diff --git a/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/DefaultLogHandler.java b/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/DefaultLogHandler.java new file mode 100644 index 00000000000..7f4a9a47419 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/DefaultLogHandler.java @@ -0,0 +1,45 @@ +package datadog.trace.instrumentation.opentracing; + +import static datadog.trace.api.DDTags.ERROR_MSG; +import static io.opentracing.log.Fields.ERROR_OBJECT; +import static io.opentracing.log.Fields.MESSAGE; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; + +/** The default implementation of the LogHandler. */ +@Slf4j +public class DefaultLogHandler implements LogHandler { + @Override + public void log(final Map fields, final AgentSpan span) { + extractError(fields, span); + log.debug("`log` method is not implemented. Doing nothing"); + } + + @Override + public void log( + final long timestampMicroseconds, final Map fields, final AgentSpan span) { + extractError(fields, span); + log.debug("`log` method is not implemented. Doing nothing"); + } + + @Override + public void log(final String event, final AgentSpan span) { + log.debug("`log` method is not implemented. Provided log: {}", event); + } + + @Override + public void log(final long timestampMicroseconds, final String event, final AgentSpan span) { + log.debug("`log` method is not implemented. Provided log: {}", event); + } + + private void extractError(final Map map, final AgentSpan span) { + if (map.get(ERROR_OBJECT) instanceof Throwable) { + final Throwable error = (Throwable) map.get(ERROR_OBJECT); + span.addThrowable(error); + } else if (map.get(MESSAGE) instanceof String) { + span.setTag(ERROR_MSG, (String) map.get(MESSAGE)); + } + } +} diff --git a/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/LogHandler.java b/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/LogHandler.java new file mode 100644 index 00000000000..610ccfa4bd4 --- /dev/null +++ b/dd-java-agent/instrumentation/opentracing/src/main/java/datadog/trace/instrumentation/opentracing/LogHandler.java @@ -0,0 +1,44 @@ +package datadog.trace.instrumentation.opentracing; + +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.util.Map; + +public interface LogHandler { + + /** + * Handles the log implementation in the Span. + * + * @param fields key:value log fields. Tracer implementations should support String, numeric, and + * boolean values; some may also support arbitrary Objects. + * @param span from which the call was made + */ + void log(Map fields, AgentSpan span); + + /** + * Handles the log implementation in the Span. + * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or + * equal to the Span's start timestamp. + * @param fields key:value log fields. Tracer implementations should support String, numeric, and + * @param span from which the call was made + */ + void log(long timestampMicroseconds, Map fields, AgentSpan span); + + /** + * Handles the log implementation in the Span.. + * + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @param span from which the call was made + */ + void log(String event, AgentSpan span); + + /** + * Handles the log implementation in the Span. + * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or + * equal to the Span's start timestamp. + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @param span from which the call was made + */ + void log(long timestampMicroseconds, String event, AgentSpan span); +} diff --git a/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/opentracing/OpenTracingTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/opentracing/OpenTracingTest.groovy new file mode 100644 index 00000000000..3c35686431b --- /dev/null +++ b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/opentracing/OpenTracingTest.groovy @@ -0,0 +1,38 @@ +package datadog.trace.agent.integration.opentracing + +import datadog.trace.api.interceptor.MutableSpan +import datadog.trace.context.TraceScope +import io.opentracing.util.GlobalTracer +import spock.lang.Specification +import spock.lang.Subject + +/** + * Simple set of tests to verify the OpenTracing instrumentation is added correctly. + */ +class OpenTracingTest extends Specification { + + @Subject + def tracer = GlobalTracer.get() + + def "test tracer registered"() { + expect: + GlobalTracer.isRegistered() + } + + def "test span/scope interfaces"() { + setup: + def span = tracer.buildSpan("test").start() + + expect: + span instanceof MutableSpan + + when: + def scope = tracer.scopeManager().activate(span, false) + + then: + scope instanceof TraceScope + + cleanup: + scope.close() + } +} diff --git a/settings.gradle b/settings.gradle index 36208afb064..827e5d14997 100644 --- a/settings.gradle +++ b/settings.gradle @@ -124,6 +124,9 @@ include ':dd-java-agent:instrumentation:netty-4.0' include ':dd-java-agent:instrumentation:netty-4.1' include ':dd-java-agent:instrumentation:okhttp-2' include ':dd-java-agent:instrumentation:okhttp-3' +include ':dd-java-agent:instrumentation:opentracing' +include ':dd-java-agent:instrumentation:opentracing:api-0.31' +include ':dd-java-agent:instrumentation:opentracing:api-0.32' include ':dd-java-agent:instrumentation:play-2.3' include ':dd-java-agent:instrumentation:play-2.4' include ':dd-java-agent:instrumentation:play-2.6' From 1ea1927f62a5c51908280780fbb672aacf8ff094 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Tue, 2 Jun 2020 10:18:22 -0400 Subject: [PATCH 4/4] Fix build --- .palantir/revapi.yml | 53 +++++++++++++++++++ .../play-perftest/play-perftest.gradle | 1 + .../opentracing/api-0.32/api-0.32.gradle | 10 ++++ dd-trace-ot/dd-trace-ot.gradle | 6 +-- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/.palantir/revapi.yml b/.palantir/revapi.yml index 9809b4e0d6e..c19cfdd2379 100644 --- a/.palantir/revapi.yml +++ b/.palantir/revapi.yml @@ -353,6 +353,59 @@ acceptedBreaks: - code: "java.class.removed" old: "class datadog.trace.core.StringCachingBigInteger" justification: "internal api" + - code: "java.class.removed" + old: "interface datadog.trace.core.scopemanager.DDScopeManager" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.DDTracer::(===datadog.trace.core.CoreTracer===)" + new: "parameter void datadog.opentracing.DDTracer::(===datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.DefaultLogHandler::log(java.lang.String,\ + \ ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.DefaultLogHandler::log(java.lang.String,\ + \ ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.DefaultLogHandler::log(java.util.Map, ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.DefaultLogHandler::log(java.util.Map, ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.DefaultLogHandler::log(long, java.lang.String,\ + \ ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.DefaultLogHandler::log(long, java.lang.String,\ + \ ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.DefaultLogHandler::log(long, java.util.Map, ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.DefaultLogHandler::log(long, java.util.Map, ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.LogHandler::log(java.lang.String, ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.LogHandler::log(java.lang.String, ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.LogHandler::log(java.util.Map, ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.LogHandler::log(java.util.Map, ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.LogHandler::log(long, java.lang.String,\ + \ ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.LogHandler::log(long, java.lang.String,\ + \ ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" + - code: "java.method.parameterTypeChanged" + old: "parameter void datadog.opentracing.LogHandler::log(long, java.util.Map, ===datadog.trace.core.DDSpan===)" + new: "parameter void datadog.opentracing.LogHandler::log(long, java.util.Map, ===datadog.trace.bootstrap.instrumentation.api.AgentSpan===)" + justification: "Use Agent API instead of Core API where possible" - code: "java.method.removed" old: "method void datadog.trace.core.serialization.FormatWriter::writeBigInteger(byte[],\ \ java.math.BigInteger, DEST) throws java.io.IOException" diff --git a/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle b/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle index a1a548c0adc..121fdfb231f 100644 --- a/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle +++ b/dd-java-agent/benchmark-integration/play-perftest/play-perftest.gradle @@ -23,6 +23,7 @@ dependencies { play project(':dd-trace-api') play project(':dd-java-agent:benchmark-integration') play group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0' + play group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' } repositories { diff --git a/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle b/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle index 7e3997d7626..afa73d0d3a5 100644 --- a/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle +++ b/dd-java-agent/instrumentation/opentracing/api-0.32/api-0.32.gradle @@ -9,10 +9,20 @@ muzzle { apply from: "$rootDir/gradle/java.gradle" +apply plugin: 'org.unbroken-dome.test-sets' + +testSets { + latestDepTest { + dirName = 'test' + } +} + dependencies { compile project(':dd-java-agent:instrumentation:opentracing') compileOnly group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' testCompile group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0' + + latestDepTestCompile group: 'io.opentracing', name: 'opentracing-util', version: '+' } diff --git a/dd-trace-ot/dd-trace-ot.gradle b/dd-trace-ot/dd-trace-ot.gradle index d818ef77b03..da91e39c234 100644 --- a/dd-trace-ot/dd-trace-ot.gradle +++ b/dd-trace-ot/dd-trace-ot.gradle @@ -14,10 +14,8 @@ minimumBranchCoverage = 0.5 minimumInstructionCoverage = 0.5 excludedClassesCoverage += [ - // These are all equals() and hashCode() - "datadog.opentracing.OTTagContext", - "datadog.opentracing.OTExtractedContext", - "datadog.opentracing.OTGenericContext", + // This is mainly equals() and hashCode() + "datadog.opentracing.OTSpanContext", // The builder is generated "datadog.opentracing.DDTracer.DDTracerBuilder" ]