Migrate method tracing instrumentation to Decorator
MODIFY
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/BaseDecorator.java
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/BaseDecorator.java
@@ -4,8 +4,10 @@ import static io.opentracing.log.Fields.ERROR_OBJECT;
import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
+import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
+import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.TreeSet;
@@ -16,11 +18,13 @@ public abstract class BaseDecorator {
protected final float traceAnalyticsSampleRate;
protected BaseDecorator() {
+ final String[] instrumentationNames = instrumentationNames();
traceAnalyticsEnabled =
- Config.traceAnalyticsIntegrationEnabled(
- new TreeSet<>(Arrays.asList(instrumentationNames())), traceAnalyticsDefault());
+ instrumentationNames.length > 0
+ && Config.traceAnalyticsIntegrationEnabled(
+ new TreeSet<>(Arrays.asList(instrumentationNames)), traceAnalyticsDefault());
float rate = 1.0f;
- for (final String name : instrumentationNames()) {
+ for (final String name : instrumentationNames) {
rate =
Config.getFloatSettingFromEnvironment(
"integration." + name + ".analytics.sample-rate", rate);
@@ -38,6 +42,12 @@ public abstract class BaseDecorator {
return false;
}
+ public Scope afterStart(final Scope scope) {
+ assert scope != null;
+ afterStart(scope.span());
+ return scope;
+ }
+
public Span afterStart(final Span span) {
assert span != null;
span.setTag(DDTags.SPAN_TYPE, spanType());
@@ -48,11 +58,23 @@ public abstract class BaseDecorator {
return span;
}
+ public Scope beforeFinish(final Scope scope) {
+ assert scope != null;
+ beforeFinish(scope.span());
+ return scope;
+ }
+
public Span beforeFinish(final Span span) {
assert span != null;
return span;
}
+ public Scope onError(final Scope scope, final Throwable throwable) {
+ assert scope != null;
+ onError(scope.span(), throwable);
+ return scope;
+ }
+
public Span onError(final Span span, final Throwable throwable) {
assert span != null;
if (throwable != null) {
@@ -61,4 +83,19 @@ public abstract class BaseDecorator {
}
return span;
}
+
+ public String spanNameForMethod(final Method method) {
+ final Class<?> declaringClass = method.getDeclaringClass();
+ String className = declaringClass.getSimpleName();
+ if (className.isEmpty()) {
+ className = declaringClass.getName();
+ if (declaringClass.getPackage() != null) {
+ final String pkgName = declaringClass.getPackage().getName();
+ if (!pkgName.isEmpty()) {
+ className = declaringClass.getName().replace(pkgName, "").substring(1);
+ }
+ }
+ }
+ return className + "." + method.getName();
+ }
}

MODIFY
dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/BaseDecoratorTest.groovy
dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/BaseDecoratorTest.groovy
package datadog.trace.agent.decorator
import datadog.trace.api.DDTags
+import io.opentracing.Scope
import io.opentracing.Span
import io.opentracing.tag.Tags
import spock.lang.Shared
@@ -52,36 +53,81 @@ class BaseDecoratorTest extends Specification {
def "test assert null span"() {
when:
- decorator.afterStart(null)
+ decorator.afterStart((Span) null)
then:
thrown(AssertionError)
when:
- decorator.onError(null, null)
+ decorator.onError((Span) null, null)
then:
thrown(AssertionError)
when:
- decorator.beforeFinish(null)
+ decorator.beforeFinish((Span) null)
then:
thrown(AssertionError)
}
+ def "test assert null scope"() {
+ when:
+ decorator.afterStart((Scope) null)
+
+ then:
+ thrown(AssertionError)
+
+ when:
+ decorator.onError((Scope) null, null)
+
+ then:
+ thrown(AssertionError)
+
+ when:
+ decorator.beforeFinish((Scope) null)
+
+ then:
+ thrown(AssertionError)
+ }
+
+ def "test assert non-null scope"() {
+ setup:
+ def span = Mock(Span)
+ def scope = Mock(Scope)
+
+ when:
+ decorator.afterStart(scope)
+
+ then:
+ 1 * scope.span() >> span
+
+ when:
+ decorator.onError(scope, null)
+
+ then:
+ 1 * scope.span() >> span
+
+ when:
+ decorator.beforeFinish(scope)
+
+ then:
+ 1 * scope.span() >> span
+ }
+
def "test analytics rate default disabled"() {
when:
- BaseDecorator dec = newDecorator(defaultEnabled)
+ BaseDecorator dec = newDecorator(defaultEnabled, hasConfigNames)
then:
dec.traceAnalyticsEnabled == defaultEnabled
- dec.traceAnalyticsSampleRate == sampleRate
+ dec.traceAnalyticsSampleRate == sampleRate.floatValue()
where:
- defaultEnabled | sampleRate
- true | 1.0
- false | 1.0
+ defaultEnabled | hasConfigNames | sampleRate
+ true | false | 1.0
+ false | false | 1.0
+ false | true | 1.0
}
def "test analytics rate enabled"() {
@@ -112,8 +158,29 @@ class BaseDecoratorTest extends Specification {
return newDecorator(false)
}
- def newDecorator(final Boolean analyticsEnabledDefault) {
- return analyticsEnabledDefault ?
+ def newDecorator(boolean analyticsEnabledDefault, boolean emptyInstrumentationNames = false) {
+ return emptyInstrumentationNames ?
+ new BaseDecorator() {
+ @Override
+ protected String[] instrumentationNames() {
+ return []
+ }
+
+ @Override
+ protected String spanType() {
+ return "test-type"
+ }
+
+ @Override
+ protected String component() {
+ return "test-component"
+ }
+
+ protected boolean traceAnalyticsDefault() {
+ return true
+ }
+ } :
+ analyticsEnabledDefault ?
new BaseDecorator() {
@Override
protected String[] instrumentationNames() {

MODIFY
dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/DatabaseClientDecoratorTest.groovy
dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/DatabaseClientDecoratorTest.groovy
@@ -75,7 +75,7 @@ class DatabaseClientDecoratorTest extends ClientDecoratorTest {
def decorator = newDecorator()
when:
- decorator.afterStart(null)
+ decorator.afterStart((Span) null)
then:
thrown(AssertionError)

MODIFY
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAdvice.java
package datadog.trace.instrumentation.trace_annotation;
-import static io.opentracing.log.Fields.ERROR_OBJECT;
+import static datadog.trace.instrumentation.trace_annotation.TraceDecorator.DECORATE;
import datadog.trace.api.Trace;
import io.opentracing.Scope;
-import io.opentracing.Span;
-import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.lang.reflect.Method;
-import java.util.Collections;
import net.bytebuddy.asm.Advice;
public class TraceAdvice {
@@ -18,34 +15,16 @@ public class TraceAdvice {
final Trace trace = method.getAnnotation(Trace.class);
String operationName = trace == null ? null : trace.operationName();
if (operationName == null || operationName.isEmpty()) {
- final Class<?> declaringClass = method.getDeclaringClass();
- String className = declaringClass.getSimpleName();
- if (className.isEmpty()) {
- className = declaringClass.getName();
- if (declaringClass.getPackage() != null) {
- final String pkgName = declaringClass.getPackage().getName();
- if (!pkgName.isEmpty()) {
- className = declaringClass.getName().replace(pkgName, "").substring(1);
+ operationName = DECORATE.spanNameForMethod(method);
}
- }
- }
- operationName = className + "." + method.getName();
- }
-
- return GlobalTracer.get()
- .buildSpan(operationName)
- .withTag(Tags.COMPONENT.getKey(), "trace")
- .startActive(true);
+ return DECORATE.afterStart(GlobalTracer.get().buildSpan(operationName).startActive(true));
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
- if (throwable != null) {
- final Span span = scope.span();
- Tags.ERROR.set(span, true);
- span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
- }
+ DECORATE.onError(scope, throwable);
+ DECORATE.beforeFinish(scope);
scope.close();
}
}

MODIFY
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java
@@ -82,6 +82,13 @@ public final class TraceAnnotationsInstrumentation extends Instrumenter.Default
return safeHasSuperType(declaresMethod(isAnnotatedWith(methodTraceMatcher)));
}
+ @Override
+ public String[] helperClassNames() {
+ return new String[] {
+ "datadog.trace.agent.decorator.BaseDecorator", packageName + ".TraceDecorator",
+ };
+ }
+
@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return Collections.singletonMap(

MODIFY
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java
@@ -120,6 +120,13 @@ public class TraceConfigInstrumentation implements Instrumenter {
return safeHasSuperType(named(className));
}
+ @Override
+ public String[] helperClassNames() {
+ return new String[] {
+ "datadog.trace.agent.decorator.BaseDecorator", packageName + ".TraceDecorator",
+ };
+ }
+
@Override
public Map<ElementMatcher<? super MethodDescription>, String> transformers() {
ElementMatcher.Junction<MethodDescription> methodMatchers = null;

ADD
dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceDecorator.java
+package datadog.trace.instrumentation.trace_annotation;
+
+import datadog.trace.agent.decorator.BaseDecorator;
+
+public class TraceDecorator extends BaseDecorator {
+ public static TraceDecorator DECORATE = new TraceDecorator();
+
+ @Override
+ protected String[] instrumentationNames() {
+ return new String[0];
+ }
+
+ @Override
+ protected String spanType() {
+ return null;
+ }
+
+ @Override
+ protected String component() {
+ return "trace";
+ }
+}

Migrate method tracing instrumentation to Decorator