Merge pull request #969 from DataDog/labbati/jax-rs-op-name

Static operation names for JaxRS instrumentation to be used as root span
This commit is contained in:
Tyler Benson 2019-08-30 14:09:46 -04:00 committed by GitHub
commit a693c42dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 12 deletions

View File

@ -3,6 +3,7 @@ package datadog.trace.instrumentation.jaxrs;
import static datadog.trace.bootstrap.WeakMap.Provider.newWeakMap; import static datadog.trace.bootstrap.WeakMap.Provider.newWeakMap;
import datadog.trace.agent.decorator.BaseDecorator; import datadog.trace.agent.decorator.BaseDecorator;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags; import datadog.trace.api.DDTags;
import datadog.trace.bootstrap.WeakMap; import datadog.trace.bootstrap.WeakMap;
import io.opentracing.Scope; import io.opentracing.Scope;
@ -36,13 +37,41 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
return "jax-rs-controller"; return "jax-rs-controller";
} }
public void updateParent(final Scope scope, final Method method) { public void onControllerStart(final Scope scope, final Scope parent, final Method method) {
final String resourceName = getPathResourceName(method);
updateParent(parent, resourceName);
final Span span = scope.span();
span.setTag(DDTags.SPAN_TYPE, DDSpanTypes.HTTP_SERVER);
// When jax-rs is the root, we want to name using the path, otherwise use the class/method.
final boolean isRootScope = parent == null;
if (isRootScope && !resourceName.isEmpty()) {
span.setTag(DDTags.RESOURCE_NAME, resourceName);
} else {
span.setTag(DDTags.RESOURCE_NAME, DECORATE.spanNameForMethod(method));
}
}
private void updateParent(final Scope scope, final String resourceName) {
if (scope == null) { if (scope == null) {
return; return;
} }
final Span span = scope.span(); final Span span = scope.span();
Tags.COMPONENT.set(span, "jax-rs"); Tags.COMPONENT.set(span, "jax-rs");
if (!resourceName.isEmpty()) {
span.setTag(DDTags.RESOURCE_NAME, resourceName);
}
}
/**
* Returns the resource name given a JaxRS annotated method. Results are cached so this method can
* be called multiple times without significantly impacting performance.
*
* @return The result can be an empty string but will never be {@code null}.
*/
private String getPathResourceName(final Method method) {
final Class<?> target = method.getDeclaringClass(); final Class<?> target = method.getDeclaringClass();
Map<Method, String> classMap = resourceNames.get(target); Map<Method, String> classMap = resourceNames.get(target);
@ -61,9 +90,7 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
classMap.put(method, resourceName); classMap.put(method, resourceName);
} }
if (!resourceName.isEmpty()) { return resourceName;
span.setTag(DDTags.RESOURCE_NAME, resourceName);
}
} }
private String locateHttpMethod(final Method method) { private String locateHttpMethod(final Method method) {

View File

@ -10,6 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.Instrumenter;
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 java.util.Map; import java.util.Map;
@ -21,6 +22,8 @@ import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class) @AutoService(Instrumenter.class)
public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default { public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default {
private static final String JAX_ENDPOINT_OPERATION_NAME = "jax-rs.request";
public JaxRsAnnotationsInstrumentation() { public JaxRsAnnotationsInstrumentation() {
super("jax-rs", "jaxrs", "jax-rs-annotations"); super("jax-rs", "jaxrs", "jax-rs-annotations");
} }
@ -57,13 +60,12 @@ public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default
@Advice.OnMethodEnter(suppress = Throwable.class) @Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope nameSpan(@Advice.Origin final Method method) { public static Scope nameSpan(@Advice.Origin final Method method) {
final Tracer tracer = GlobalTracer.get();
// Rename the parent span according to the path represented by these annotations. // Rename the parent span according to the path represented by these annotations.
final Scope scope = GlobalTracer.get().scopeManager().active(); final Scope parent = tracer.scopeManager().active();
DECORATE.updateParent(scope, method); final Scope scope = tracer.buildSpan(JAX_ENDPOINT_OPERATION_NAME).startActive(true);
DECORATE.onControllerStart(scope, parent, method);
// Now create a span representing the method execution. return DECORATE.afterStart(scope);
final String operationName = DECORATE.spanNameForMethod(method);
return DECORATE.afterStart(GlobalTracer.get().buildSpan(operationName).startActive(true));
} }
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)

View File

@ -14,7 +14,31 @@ import static datadog.trace.instrumentation.jaxrs.JaxRsAnnotationsDecorator.DECO
class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner { class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
def "span named '#name' from annotations on class"() { def "instrumentation can be used as root span and resource is set to METHOD PATH"() {
setup:
new Jax() {
@POST
@Path("/a")
void call() {}
}.call()
expect:
assertTraces(1) {
trace(0, 1) {
span(0) {
operationName "jax-rs.request"
resourceName "POST /a"
spanType "web"
tags {
"$Tags.COMPONENT.key" "jax-rs-controller"
defaultTags()
}
}
}
}
}
def "span named '#name' from annotations on class when is not root span"() {
setup: setup:
def startingCacheSize = DECORATE.resourceNames.size() def startingCacheSize = DECORATE.resourceNames.size()
runUnderTrace("test") { runUnderTrace("test") {
@ -34,8 +58,9 @@ class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
} }
} }
span(1) { span(1) {
operationName "${className}.call" operationName "jax-rs.request"
resourceName "${className}.call" resourceName "${className}.call"
spanType "web"
childOf span(0) childOf span(0)
tags { tags {
"$Tags.COMPONENT.key" "jax-rs-controller" "$Tags.COMPONENT.key" "jax-rs-controller"