diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java index 09d437eb70..48278908b7 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java @@ -181,43 +181,45 @@ public abstract class BaseTracer { /** * This method is used to generate an acceptable span (operation) name based on a given method * reference. Anonymous classes are named based on their parent. + * + * @deprecated Use {@link SpanNames#spanNameForMethod(Method)}. */ + @Deprecated public static String spanNameForMethod(Method method) { - return spanNameForMethod(method.getDeclaringClass(), method.getName()); + return SpanNames.spanNameForMethod(method); } /** * This method is used to generate an acceptable span (operation) name based on a given method * reference. Anonymous classes are named based on their parent. + * + * @deprecated Use {@link SpanNames#spanNameForMethod(Class, Method)}. */ + @Deprecated public static String spanNameForMethod(Class clazz, @Nullable Method method) { - return spanNameForMethod(clazz, method == null ? "" : method.getName()); + return SpanNames.spanNameForMethod(clazz, method); } /** * This method is used to generate an acceptable span (operation) name based on a given method * reference. Anonymous classes are named based on their parent. + * + * @deprecated Use {@link SpanNames#spanNameForMethod(Class, String)}. */ + @Deprecated public static String spanNameForMethod(Class cl, String methodName) { - return spanNameForClass(cl) + "." + methodName; + return SpanNames.spanNameForMethod(cl, methodName); } /** * This method is used to generate an acceptable span (operation) name based on a given class * reference. Anonymous classes are named based on their parent. + * + * @deprecated Use {@link SpanNames#spanNameForClass(Class)}. */ + @Deprecated public static String spanNameForClass(Class clazz) { - if (!clazz.isAnonymousClass()) { - return clazz.getSimpleName(); - } - String className = clazz.getName(); - if (clazz.getPackage() != null) { - String pkgName = clazz.getPackage().getName(); - if (!pkgName.isEmpty()) { - className = className.substring(pkgName.length() + 1); - } - } - return className; + return SpanNames.spanNameForClass(clazz); } /** Ends the execution of a span stored in the passed {@code context}. */ diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/SpanNames.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/SpanNames.java new file mode 100644 index 0000000000..b967eb9213 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/SpanNames.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.tracer; + +import java.lang.reflect.Method; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class SpanNames { + /** + * This method is used to generate an acceptable span (operation) name based on a given method + * reference. Anonymous classes are named based on their parent. + */ + public static String spanNameForMethod(Method method) { + return spanNameForMethod(method.getDeclaringClass(), method.getName()); + } + + /** + * This method is used to generate an acceptable span (operation) name based on a given method + * reference. Anonymous classes are named based on their parent. + */ + public static String spanNameForMethod(Class clazz, @Nullable Method method) { + return spanNameForMethod(clazz, method == null ? "" : method.getName()); + } + + /** + * This method is used to generate an acceptable span (operation) name based on a given method + * reference. Anonymous classes are named based on their parent. + */ + public static String spanNameForMethod(Class cl, String methodName) { + return spanNameForClass(cl) + "." + methodName; + } + + /** + * This method is used to generate an acceptable span (operation) name based on a given class + * reference. Anonymous classes are named based on their parent. + */ + public static String spanNameForClass(Class clazz) { + if (!clazz.isAnonymousClass()) { + return clazz.getSimpleName(); + } + String className = clazz.getName(); + if (clazz.getPackage() != null) { + String pkgName = clazz.getPackage().getName(); + if (!pkgName.isEmpty()) { + className = className.substring(pkgName.length() + 1); + } + } + return className; + } + + private SpanNames() {} +} diff --git a/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/SpanNamesTest.groovy b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/SpanNamesTest.groovy new file mode 100644 index 0000000000..5b506e92dd --- /dev/null +++ b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/SpanNamesTest.groovy @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.tracer + +import org.spockframework.util.ReflectionUtil +import spock.lang.Specification + +class SpanNamesTest extends Specification { + + def "test spanNameForClass"() { + when: + String result = SpanNames.spanNameForClass(clazz) + + then: + result == expected + + where: + clazz | expected + SpanNamesTest | "SpanNamesTest" + SpanNames | "SpanNames" + } + + def "test spanNameForMethod"() { + when: + String result = SpanNames.spanNameForMethod(method) + + then: + result == expected + + where: + method | expected + ReflectionUtil.getMethodByName(SpanNames, "spanNameForClass") | "SpanNames.spanNameForClass" + ReflectionUtil.getMethodByName(String, "length") | "String.length" + } + + def "test spanNameForMethod with class"() { + when: + String result = SpanNames.spanNameForMethod(clazz, method) + + then: + result == expected + + where: + clazz | method | expected + SpanNames | ReflectionUtil.getMethodByName(SpanNames, "spanNameForClass") | "SpanNames.spanNameForClass" + SpanNames | "test" | "SpanNames.test" + } +} diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java index c58ebed698..6b3baea5c9 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentation.java @@ -7,7 +7,8 @@ package io.opentelemetry.javaagent.instrumentation.methods; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.safeHasSuperType; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; -import static io.opentelemetry.javaagent.instrumentation.methods.MethodTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; +import static io.opentelemetry.javaagent.instrumentation.methods.MethodInstrumenters.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.named; import io.opentelemetry.context.Context; @@ -62,21 +63,23 @@ public class MethodInstrumentation implements TypeInstrumentation { @Advice.Origin Method method, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - context = tracer().startSpan(method); + Context parentContext = currentContext(); + if (!instrumenter().shouldStart(parentContext, method)) { + return; + } + + context = instrumenter().start(parentContext, method); scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( + @Advice.Origin Method method, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope, @Advice.Thrown Throwable throwable) { scope.close(); - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - tracer().end(context); - } + instrumenter().end(context, method, null, throwable); } } } diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java index eb3d9732c3..17e776ee54 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java @@ -53,7 +53,7 @@ public class MethodInstrumentationModule extends InstrumentationModule { public List getMuzzleHelperClassNames() { return typeInstrumentations.isEmpty() ? emptyList() - : singletonList("io.opentelemetry.javaagent.instrumentation.methods.MethodTracer"); + : singletonList("io.opentelemetry.javaagent.instrumentation.methods.MethodInstrumenters"); } @Override diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumenters.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumenters.java new file mode 100644 index 0000000000..8d30c966aa --- /dev/null +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumenters.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.methods; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.tracer.SpanNames; +import java.lang.reflect.Method; + +public final class MethodInstrumenters { + private static final String INSTRUMENTATION_NAME = + "io.opentelemetry.javaagent.external-annotations"; + + private static final Instrumenter INSTRUMENTER; + + static { + SpanNameExtractor spanName = SpanNames::spanNameForMethod; + + INSTRUMENTER = + Instrumenter.newBuilder( + GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanName) + .newInstrumenter(SpanKindExtractor.alwaysInternal()); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private MethodInstrumenters() {} +} diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodTracer.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodTracer.java deleted file mode 100644 index b60cd3c9f5..0000000000 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodTracer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.methods; - -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.tracer.BaseTracer; -import java.lang.reflect.Method; - -public class MethodTracer extends BaseTracer { - private static final MethodTracer TRACER = new MethodTracer(); - - public static MethodTracer tracer() { - return TRACER; - } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.javaagent.external-annotations"; - } - - public Context startSpan(Method method) { - return startSpan(spanNameForMethod(method)); - } -}