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 datadog.trace.agent.decorator.BaseDecorator;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags;
import datadog.trace.bootstrap.WeakMap;
import io.opentracing.Scope;
@ -36,13 +37,41 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
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) {
return;
}
final Span span = scope.span();
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();
Map<Method, String> classMap = resourceNames.get(target);
@ -61,9 +90,7 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
classMap.put(method, resourceName);
}
if (!resourceName.isEmpty()) {
span.setTag(DDTags.RESOURCE_NAME, resourceName);
}
return resourceName;
}
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 datadog.trace.agent.tooling.Instrumenter;
import io.opentracing.Scope;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
import java.lang.reflect.Method;
import java.util.Map;
@ -21,6 +22,8 @@ import net.bytebuddy.matcher.ElementMatcher;
@AutoService(Instrumenter.class)
public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default {
private static final String JAX_ENDPOINT_OPERATION_NAME = "jax-rs.request";
public JaxRsAnnotationsInstrumentation() {
super("jax-rs", "jaxrs", "jax-rs-annotations");
}
@ -57,13 +60,12 @@ public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default
@Advice.OnMethodEnter(suppress = Throwable.class)
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.
final Scope scope = GlobalTracer.get().scopeManager().active();
DECORATE.updateParent(scope, method);
// Now create a span representing the method execution.
final String operationName = DECORATE.spanNameForMethod(method);
return DECORATE.afterStart(GlobalTracer.get().buildSpan(operationName).startActive(true));
final Scope parent = tracer.scopeManager().active();
final Scope scope = tracer.buildSpan(JAX_ENDPOINT_OPERATION_NAME).startActive(true);
DECORATE.onControllerStart(scope, parent, method);
return DECORATE.afterStart(scope);
}
@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 {
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:
def startingCacheSize = DECORATE.resourceNames.size()
runUnderTrace("test") {
@ -34,8 +58,9 @@ class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
}
}
span(1) {
operationName "${className}.call"
operationName "jax-rs.request"
resourceName "${className}.call"
spanType "web"
childOf span(0)
tags {
"$Tags.COMPONENT.key" "jax-rs-controller"