Merge pull request #925 from DataDog/landerson/resourcename-on-annotation

Add resource name to the @Trace annotation
This commit is contained in:
Laplie Anderson 2019-07-19 12:43:19 -04:00 committed by GitHub
commit 22dc30526a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 238 additions and 3 deletions

View File

@ -2,8 +2,10 @@ package datadog.trace.instrumentation.trace_annotation;
import static datadog.trace.instrumentation.trace_annotation.TraceDecorator.DECORATE; import static datadog.trace.instrumentation.trace_annotation.TraceDecorator.DECORATE;
import datadog.trace.api.DDTags;
import datadog.trace.api.Trace; import datadog.trace.api.Trace;
import io.opentracing.Scope; import io.opentracing.Scope;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer; import io.opentracing.util.GlobalTracer;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
@ -12,12 +14,20 @@ public class TraceAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope startSpan(@Advice.Origin final Method method) { public static Scope startSpan(@Advice.Origin final Method method) {
final Trace trace = method.getAnnotation(Trace.class); final Trace traceAnnotation = method.getAnnotation(Trace.class);
String operationName = trace == null ? null : trace.operationName(); String operationName = traceAnnotation == null ? null : traceAnnotation.operationName();
if (operationName == null || operationName.isEmpty()) { if (operationName == null || operationName.isEmpty()) {
operationName = DECORATE.spanNameForMethod(method); operationName = DECORATE.spanNameForMethod(method);
} }
return DECORATE.afterStart(GlobalTracer.get().buildSpan(operationName).startActive(true));
Tracer.SpanBuilder spanBuilder = GlobalTracer.get().buildSpan(operationName);
final String resourceName = traceAnnotation == null ? null : traceAnnotation.resourceName();
if (resourceName != null && !resourceName.isEmpty()) {
spanBuilder = spanBuilder.withTag(DDTags.RESOURCE_NAME, resourceName);
}
return DECORATE.afterStart(spanBuilder.startActive(true));
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)

View File

@ -38,6 +38,77 @@ class TraceAnnotationsTest extends AgentTestRunner {
} }
} }
def "test simple case with only operation name set"() {
setup:
// Test single span in new trace
SayTracedHello.sayHA()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "test"
resourceName "SAY_HA"
operationName "SAY_HA"
spanType "DB"
parent()
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
}
}
}
def "test simple case with only resource name set"() {
setup:
// Test single span in new trace
SayTracedHello.sayHelloOnlyResourceSet()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "test"
resourceName "WORLD"
operationName "SayTracedHello.sayHelloOnlyResourceSet"
parent()
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
}
}
}
def "test simple case with both resource and operation name set"() {
setup:
// Test single span in new trace
SayTracedHello.sayHAWithResource()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
serviceName "test"
resourceName "EARTH"
operationName "SAY_HA"
spanType "DB"
parent()
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
}
}
}
def "test complex case annotations"() { def "test complex case annotations"() {
when: when:
// Test new trace with 2 children spans // Test new trace with 2 children spans
@ -82,6 +153,94 @@ class TraceAnnotationsTest extends AgentTestRunner {
} }
} }
def "test complex case with resource name at top level"() {
when:
// Test new trace with 2 children spans
SayTracedHello.sayHELLOsayHAWithResource()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
resourceName "WORLD"
operationName "NEW_TRACE"
parent()
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
span(1) {
resourceName "SAY_HA"
operationName "SAY_HA"
spanType "DB"
childOf span(0)
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
span(2) {
serviceName "test"
resourceName "SayTracedHello.sayHello"
operationName "SayTracedHello.sayHello"
childOf span(0)
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
}
}
}
def "test complex case with resource name at various levels"() {
when:
// Test new trace with 2 children spans
SayTracedHello.sayHELLOsayHAMixedResourceChildren()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
resourceName "WORLD"
operationName "NEW_TRACE"
parent()
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
span(1) {
resourceName "EARTH"
operationName "SAY_HA"
spanType "DB"
childOf span(0)
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
span(2) {
serviceName "test"
resourceName "SayTracedHello.sayHello"
operationName "SayTracedHello.sayHello"
childOf span(0)
errored false
tags {
"$Tags.COMPONENT.key" "trace"
defaultTags()
}
}
}
}
}
def "test exception exit"() { def "test exception exit"() {
setup: setup:
@ -111,6 +270,35 @@ class TraceAnnotationsTest extends AgentTestRunner {
} }
} }
def "test exception exit with resource name"() {
setup:
TEST_TRACER.addDecorator(new ErrorFlag())
Throwable error = null
try {
SayTracedHello.sayERRORWithResource()
} catch (final Throwable ex) {
error = ex
}
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
resourceName "WORLD"
operationName "ERROR"
errored true
tags {
"$Tags.COMPONENT.key" "trace"
errorTags(error.class)
defaultTags()
}
}
}
}
}
def "test annonymous class annotations"() { def "test annonymous class annotations"() {
setup: setup:
// Test anonymous classes with package. // Test anonymous classes with package.

View File

@ -15,6 +15,13 @@ public class SayTracedHello {
return "hello!"; return "hello!";
} }
@Trace(resourceName = "WORLD")
public static String sayHelloOnlyResourceSet() {
new StringTag(DDTags.SERVICE_NAME)
.set(GlobalTracer.get().scopeManager().active().span(), "test");
return "hello!";
}
@Trace(operationName = "SAY_HA") @Trace(operationName = "SAY_HA")
public static String sayHA() { public static String sayHA() {
new StringTag(DDTags.SERVICE_NAME) new StringTag(DDTags.SERVICE_NAME)
@ -23,6 +30,14 @@ public class SayTracedHello {
return "HA!!"; return "HA!!";
} }
@Trace(operationName = "SAY_HA", resourceName = "EARTH")
public static String sayHAWithResource() {
new StringTag(DDTags.SERVICE_NAME)
.set(GlobalTracer.get().scopeManager().active().span(), "test");
new StringTag(DDTags.SPAN_TYPE).set(GlobalTracer.get().scopeManager().active().span(), "DB");
return "HA EARTH!!";
}
@Trace(operationName = "NEW_TRACE") @Trace(operationName = "NEW_TRACE")
public static String sayHELLOsayHA() { public static String sayHELLOsayHA() {
new StringTag(DDTags.SERVICE_NAME) new StringTag(DDTags.SERVICE_NAME)
@ -30,11 +45,30 @@ public class SayTracedHello {
return sayHello() + sayHA(); return sayHello() + sayHA();
} }
@Trace(operationName = "NEW_TRACE", resourceName = "WORLD")
public static String sayHELLOsayHAWithResource() {
new StringTag(DDTags.SERVICE_NAME)
.set(GlobalTracer.get().scopeManager().active().span(), "test2");
return sayHello() + sayHA();
}
@Trace(operationName = "NEW_TRACE", resourceName = "WORLD")
public static String sayHELLOsayHAMixedResourceChildren() {
new StringTag(DDTags.SERVICE_NAME)
.set(GlobalTracer.get().scopeManager().active().span(), "test2");
return sayHello() + sayHAWithResource();
}
@Trace(operationName = "ERROR") @Trace(operationName = "ERROR")
public static String sayERROR() { public static String sayERROR() {
throw new RuntimeException(); throw new RuntimeException();
} }
@Trace(operationName = "ERROR", resourceName = "WORLD")
public static String sayERRORWithResource() {
throw new RuntimeException();
}
public static String fromCallable() throws Exception { public static String fromCallable() throws Exception {
return new Callable<String>() { return new Callable<String>() {
@com.newrelic.api.agent.Trace @com.newrelic.api.agent.Trace

View File

@ -13,4 +13,7 @@ public @interface Trace {
/** The operation name to set. By default it takes the method's name */ /** The operation name to set. By default it takes the method's name */
String operationName() default ""; String operationName() default "";
/** The resource name. By default it uses the same value as the operation name */
String resourceName() default "";
} }