Use static operation names for JaxRS instrumentation
MODIFY
dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsDecorator.java
dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsDecorator.java
@@ -43,6 +43,27 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
final Span span = scope.span();
Tags.COMPONENT.set(span, "jax-rs");
+ String resourceName = getResourceName(method);
+ if (!resourceName.isEmpty()) {
+ span.setTag(DDTags.RESOURCE_NAME, resourceName);
+ }
+ }
+
+ public void updateCurrentScope(final Scope scope, final Method method) {
+ String resourceName = getResourceName(method);
+ final Span span = scope.span();
+ 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 on performance.
+ *
+ * @return The result can be an empty string but will never be {@code null}.
+ */
+ private String getResourceName(final Method method) {
final Class<?> target = method.getDeclaringClass();
Map<Method, String> classMap = resourceNames.get(target);
@@ -61,9 +82,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) {

MODIFY
dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java
dd-java-agent/instrumentation/jax-rs-annotations/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsAnnotationsInstrumentation.java
@@ -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.endpoint";
+
public JaxRsAnnotationsInstrumentation() {
super("jax-rs", "jaxrs", "jax-rs-annotations");
}
@@ -58,12 +61,12 @@ public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope nameSpan(@Advice.Origin final Method method) {
// 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 = GlobalTracer.get().scopeManager().active();
+ Tracer.SpanBuilder span = GlobalTracer.get().buildSpan(JAX_ENDPOINT_OPERATION_NAME);
+ Scope scope = span.startActive(true);
+ DECORATE.updateParent(parent, method);
+ DECORATE.updateCurrentScope(scope, method);
+ return DECORATE.afterStart(scope);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)

MODIFY
dd-java-agent/instrumentation/jax-rs-annotations/src/test/groovy/JaxRsAnnotationsInstrumentationTest.groovy
dd-java-agent/instrumentation/jax-rs-annotations/src/test/groovy/JaxRsAnnotationsInstrumentationTest.groovy
@@ -14,6 +14,29 @@ import static datadog.trace.instrumentation.jaxrs.JaxRsAnnotationsDecorator.DECO
class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
+ def "instrumentation can be used as root span and relevant tags are set"() {
+ setup:
+ new Jax() {
+ @POST
+ @Path("/a")
+ void call() {}
+ }.call()
+
+ expect:
+ assertTraces(1) {
+ trace(0, 1) {
+ span(0) {
+ operationName "jax-rs.endpoint"
+ resourceName 'POST /a'
+ tags {
+ "$Tags.COMPONENT.key" "jax-rs-controller"
+ defaultTags()
+ }
+ }
+ }
+ }
+ }
+
def "span named '#name' from annotations on class"() {
setup:
def startingCacheSize = DECORATE.resourceNames.size()
@@ -34,8 +57,8 @@ class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
}
}
span(1) {
- operationName "${className}.call"
- resourceName "${className}.call"
+ operationName "jax-rs.endpoint"
+ resourceName name
childOf span(0)
tags {
"$Tags.COMPONENT.key" "jax-rs-controller"

Use static operation names for JaxRS instrumentation