Update methods-javaagent to Instrumenter API (#3070)

* Update methods-javaagent to Instrumenter API

Signed-off-by: dengliming <liming.d.pro@gmail.com>

* introduce SpanNames

Signed-off-by: dengliming <liming.d.pro@gmail.com>

* Add test for SpanNames

Signed-off-by: dengliming <liming.d.pro@gmail.com>

* Fix merge

* Codenarc

* Remove unused dep

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
dengliming 2021-05-29 08:23:50 +08:00 committed by GitHub
parent b5f949afb2
commit ca5b792f95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 168 additions and 49 deletions

View File

@ -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 ? "<unknown>" : 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}. */

View File

@ -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 ? "<unknown>" : 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() {}
}

View File

@ -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"
}
}

View File

@ -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);
}
}
}

View File

@ -53,7 +53,7 @@ public class MethodInstrumentationModule extends InstrumentationModule {
public List<String> getMuzzleHelperClassNames() {
return typeInstrumentations.isEmpty()
? emptyList()
: singletonList("io.opentelemetry.javaagent.instrumentation.methods.MethodTracer");
: singletonList("io.opentelemetry.javaagent.instrumentation.methods.MethodInstrumenters");
}
@Override

View File

@ -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<Method, Void> INSTRUMENTER;
static {
SpanNameExtractor<Method> spanName = SpanNames::spanNameForMethod;
INSTRUMENTER =
Instrumenter.<Method, Void>newBuilder(
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanName)
.newInstrumenter(SpanKindExtractor.alwaysInternal());
}
public static Instrumenter<Method, Void> instrumenter() {
return INSTRUMENTER;
}
private MethodInstrumenters() {}
}

View File

@ -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));
}
}