Update jaxrs-1.0 to Instrumenter API
RENAME
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxRsAnnotationsTracer.java
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/HandlerData.java
package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
-import io.opentelemetry.api.trace.Span;
-import io.opentelemetry.api.trace.SpanBuilder;
-import io.opentelemetry.api.trace.SpanKind;
-import io.opentelemetry.context.Context;
-import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
-import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
-import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
-import io.opentelemetry.instrumentation.api.tracer.SpanNames;
import io.opentelemetry.javaagent.bootstrap.jaxrs.ClassHierarchyIterable;
-import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
@@ -22,15 +13,9 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
-public class JaxRsAnnotationsTracer extends BaseTracer {
+public class HandlerData {
- private static final JaxRsAnnotationsTracer TRACER = new JaxRsAnnotationsTracer();
-
- public static JaxRsAnnotationsTracer tracer() {
- return TRACER;
- }
-
- private final ClassValue<Map<Method, String>> spanNames =
+ private static final ClassValue<Map<Method, String>> serverSpanNames =
new ClassValue<Map<Method, String>>() {
@Override
protected Map<Method, String> computeValue(Class<?> type) {
@@ -38,37 +23,20 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
}
};
- public Context startSpan(Class<?> target, Method method) {
- String pathBasedSpanName = getPathSpanName(target, method);
- Context parentContext = Context.current();
- Span serverSpan = ServerSpan.fromContextOrNull(parentContext);
+ private final Class<?> target;
+ private final Method method;
- // When jax-rs is the root, we want to name using the path, otherwise use the class/method.
- String spanName;
- if (serverSpan == null) {
- spanName = pathBasedSpanName;
- } else {
- spanName = SpanNames.fromMethod(target, method);
- updateServerSpanName(parentContext, serverSpan, pathBasedSpanName);
+ public HandlerData(Class<?> target, Method method) {
+ this.target = target;
+ this.method = method;
}
- SpanBuilder spanBuilder = spanBuilder(parentContext, spanName, SpanKind.INTERNAL);
- setCodeAttributes(spanBuilder, target, method);
- Span span = spanBuilder.startSpan();
- return parentContext.with(span);
+ public Class<?> codeClass() {
+ return target;
}
- private static void setCodeAttributes(SpanBuilder spanBuilder, Class<?> target, Method method) {
- spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, target.getName());
- if (method != null) {
- spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, method.getName());
- }
- }
-
- private static void updateServerSpanName(Context context, Span span, String spanName) {
- if (!spanName.isEmpty()) {
- span.updateName(ServletContextPath.prepend(context, spanName));
- }
+ public String methodName() {
+ return method.getName();
}
/**
@@ -77,8 +45,8 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
*
* @return The result can be an empty string but will never be {@code null}.
*/
- private String getPathSpanName(Class<?> target, Method method) {
- Map<Method, String> classMap = spanNames.get(target);
+ String getServerSpanName() {
+ Map<Method, String> classMap = serverSpanNames.get(target);
String spanName = classMap.get(method);
if (spanName == null) {
String httpMethod = null;
@@ -168,11 +136,12 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
StringBuilder spanNameBuilder = new StringBuilder();
boolean skipSlash = false;
if (classPath != null) {
- if (!classPath.value().startsWith("/")) {
+ String classPathValue = classPath.value();
+ if (!classPathValue.startsWith("/")) {
spanNameBuilder.append("/");
}
- spanNameBuilder.append(classPath.value());
- skipSlash = classPath.value().endsWith("/");
+ spanNameBuilder.append(classPathValue);
+ skipSlash = classPathValue.endsWith("/") || classPathValue.isEmpty();
}
if (methodPath != null) {
@@ -189,9 +158,4 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
return spanNameBuilder.toString().trim();
}
-
- @Override
- protected String getInstrumentationName() {
- return "io.opentelemetry.jaxrs-1.0";
- }
}

RENAME
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxRsAnnotationsInstrumentation.java
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxrsAnnotationsInstrumentation.java
@@ -8,7 +8,7 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperMethod;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType;
-import static io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0.JaxRsAnnotationsTracer.tracer;
+import static io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0.JaxrsSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
@@ -17,16 +17,18 @@ import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.CallDepth;
+import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import java.lang.reflect.Method;
import javax.ws.rs.Path;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
-public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
+public class JaxrsAnnotationsInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderOptimization() {
@@ -55,7 +57,7 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
"javax.ws.rs.OPTIONS",
"javax.ws.rs.POST",
"javax.ws.rs.PUT")))),
- JaxRsAnnotationsInstrumentation.class.getName() + "$JaxRsAnnotationsAdvice");
+ JaxrsAnnotationsInstrumentation.class.getName() + "$JaxRsAnnotationsAdvice");
}
@SuppressWarnings("unused")
@@ -66,13 +68,27 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
@Advice.This Object target,
@Advice.Origin Method method,
@Advice.Local("otelCallDepth") CallDepth callDepth,
+ @Advice.Local("otelHandlerData") HandlerData handlerData,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
callDepth = CallDepth.forClass(Path.class);
if (callDepth.getAndIncrement() > 0) {
return;
}
- context = tracer().startSpan(target.getClass(), method);
+
+ Context parentContext = Java8BytecodeBridge.currentContext();
+ handlerData = new HandlerData(target.getClass(), method);
+
+ ServerSpanNaming.updateServerSpanName(
+ parentContext,
+ ServerSpanNaming.Source.CONTROLLER,
+ JaxrsServerSpanNaming.getServerSpanNameSupplier(parentContext, handlerData));
+
+ if (!instrumenter().shouldStart(parentContext, handlerData)) {
+ return;
+ }
+
+ context = instrumenter().start(parentContext, handlerData);
scope = context.makeCurrent();
}
@@ -80,18 +96,18 @@ public class JaxRsAnnotationsInstrumentation implements TypeInstrumentation {
public static void stopSpan(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelCallDepth") CallDepth callDepth,
+ @Advice.Local("otelHandlerData") HandlerData handlerData,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (callDepth.decrementAndGet() > 0) {
return;
}
- scope.close();
- if (throwable == null) {
- tracer().end(context);
- } else {
- tracer().endExceptionally(context, throwable);
+ if (scope == null) {
+ return;
}
+ scope.close();
+ instrumenter().end(context, handlerData, null, throwable);
}
}
}

ADD
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxrsCodeAttributesExtractor.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
+
+import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+public class JaxrsCodeAttributesExtractor extends CodeAttributesExtractor<HandlerData, Void> {
+ @Override
+ protected @Nullable Class<?> codeClass(HandlerData handlerData) {
+ return handlerData.codeClass();
+ }
+
+ @Override
+ protected @Nullable String methodName(HandlerData handlerData) {
+ return handlerData.methodName();
+ }
+
+ @Override
+ protected @Nullable String filePath(HandlerData handlerData) {
+ return null;
+ }
+
+ @Override
+ protected @Nullable Long lineNumber(HandlerData handlerData) {
+ return null;
+ }
+}

RENAME
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxRsInstrumentationModule.java
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxrsInstrumentationModule.java
@@ -16,8 +16,8 @@ import java.util.List;
import net.bytebuddy.matcher.ElementMatcher;
@AutoService(InstrumentationModule.class)
-public class JaxRsInstrumentationModule extends InstrumentationModule {
- public JaxRsInstrumentationModule() {
+public class JaxrsInstrumentationModule extends InstrumentationModule {
+ public JaxrsInstrumentationModule() {
super("jaxrs", "jaxrs-1.0");
}
@@ -29,6 +29,6 @@ public class JaxRsInstrumentationModule extends InstrumentationModule {
@Override
public List<TypeInstrumentation> typeInstrumentations() {
- return singletonList(new JaxRsAnnotationsInstrumentation());
+ return singletonList(new JaxrsAnnotationsInstrumentation());
}
}

ADD
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxrsServerSpanNaming.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
+
+import io.opentelemetry.context.Context;
+import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
+import io.opentelemetry.javaagent.bootstrap.jaxrs.JaxrsContextPath;
+import java.util.function.Supplier;
+
+public class JaxrsServerSpanNaming {
+
+ public static Supplier<String> getServerSpanNameSupplier(
+ Context context, HandlerData handlerData) {
+ return () -> {
+ String pathBasedSpanName = handlerData.getServerSpanName();
+ // If path based name is empty skip prepending context path so that path based name would
+ // remain as an empty string for which we skip updating span name. Path base span name is
+ // empty when method and class don't have a jax-rs path annotation, this can happen when
+ // creating an "abort" span, see RequestContextHelper.
+ if (!pathBasedSpanName.isEmpty()) {
+ pathBasedSpanName = JaxrsContextPath.prepend(context, pathBasedSpanName);
+ pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName);
+ }
+ return pathBasedSpanName;
+ };
+ }
+
+ private JaxrsServerSpanNaming() {}
+}

ADD
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jaxrs/v1_0/JaxrsSingletons.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor;
+
+public final class JaxrsSingletons {
+
+ public static final String ABORT_FILTER_CLASS =
+ "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.class";
+ public static final String ABORT_HANDLED =
+ "io.opentelemetry.javaagent.instrumentation.jaxrs2.filter.abort.handled";
+
+ private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jaxrs-1.0-common";
+
+ private static final Instrumenter<HandlerData, Void> INSTRUMENTER;
+
+ static {
+ CodeAttributesExtractor<HandlerData, Void> codeAttributesExtractor =
+ new JaxrsCodeAttributesExtractor();
+ SpanNameExtractor<HandlerData> spanNameExtractor =
+ CodeSpanNameExtractor.create(codeAttributesExtractor);
+
+ INSTRUMENTER =
+ Instrumenter.<HandlerData, Void>newBuilder(
+ GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor)
+ .addAttributesExtractor(codeAttributesExtractor)
+ .newInstrumenter();
+ }
+
+ public static Instrumenter<HandlerData, Void> instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ private JaxrsSingletons() {}
+}

MODIFY
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/test/groovy/JaxRsAnnotations1InstrumentationTest.groovy
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/test/groovy/JaxRsAnnotations1InstrumentationTest.groovy
@@ -20,30 +20,6 @@ import spock.lang.Unroll
class JaxRsAnnotations1InstrumentationTest extends AgentInstrumentationSpecification {
- def "instrumentation can be used as root span and resource is set to METHOD PATH"() {
- setup:
- def jax = new Jax() {
- @POST
- @Path("/a")
- void call() {
- }
- }
- jax.call()
-
- expect:
- assertTraces(1) {
- trace(0, 1) {
- span(0) {
- name "/a"
- attributes {
- "${SemanticAttributes.CODE_NAMESPACE.key}" jax.getClass().getName()
- "${SemanticAttributes.CODE_FUNCTION.key}" "call"
- }
- }
- }
- }
- }
-
@Unroll
def "span named '#paramName' from annotations on class '#className' when is not root span"() {
setup:

Update jaxrs-1.0 to Instrumenter API (#3797)