OpenTelemetry扩展中TypeTransformer applyAdviceToMethod的isConstructor()失效问题
问题描述
我尝试用OpenTelemetry JavaAgent及扩展,在某个类的构造方法被调用时添加Span实现追踪。配置代码后,给构造方法加的日志没有输出,但给普通方法(比如dummyMethod)配置时正常生效,请问我的配置哪里有问题?
相关代码
import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.named; public class ClassConstructorInstrumentation implements TypeInstrumentation { @Override public ElementMatcher<TypeDescription> typeMatcher() { return ElementMatchers .namedOneOf("org.example.ServiceManagerDummy"); } @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( isConstructor(), this.getClass().getName() + "$ConstructorSpanCreateAdvice"); // transformer.applyAdviceToMethod( // named("dummyMethod"), // this.getClass().getName() + "$ConstructorSpanCreateAdvice"); } @SuppressWarnings("unused") public static class ConstructorSpanCreateAdvice { @Advice.OnMethodEnter public static void onEnter() { System.out.println("START SPAN "); } @Advice.OnMethodExit(onThrowable = Throwable.class) public static void onExit( @Advice.Thrown Throwable throwable ) { System.out.println("END SPAN "); } } }
public class ServiceManagerDummy { public ServiceManagerDummy() { System.out.println("SERVICE MANAGER CONSTR"); dummyMethod(); } private void dummyMethod() { System.out.println("DUMMY METHOD CALLED"); } }
问题分析与解决
你的配置问题主要出在构造方法的织入时机和匹配细节上:
- 类加载顺序冲突:如果
ServiceManagerDummy在OpenTelemetry Agent及你的扩展加载之前就被类加载器初始化了,构造方法的Advice根本没机会织入。普通方法是懒加载的,后续调用时才会触发织入,所以能正常生效。 - 构造方法匹配精度不足:
isConstructor()会匹配所有构造方法,若你的类存在多个构造方法,或者织入逻辑没覆盖到当前调用的构造,就会无输出。建议明确匹配无参构造:isConstructor().and(ElementMatchers.takesArguments(0))。 - 扩展未正确注册:检查你的扩展Jar中是否存在
META-INF/services/io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation文件,文件内容必须写入你的Instrumentation类全限定名(比如org.example.ClassConstructorInstrumentation),否则Agent找不到你的扩展逻辑。 - Agent启动参数缺失:启动应用时,要确保扩展Jar通过
--otel-javaagent-extensions参数传给JavaAgent,示例命令:java -javaagent:opentelemetry-javaagent.jar --otel-javaagent-extensions=your-extension.jar -jar your-app.jar
另外,把日志替换成OpenTelemetry的Span创建逻辑,能更准确验证织入是否成功:
@SuppressWarnings("unused") public static class ConstructorSpanCreateAdvice { private static final Tracer TRACER = GlobalOpenTelemetry.getTracer("service-manager-instrumentation"); @Advice.OnMethodEnter public static void onEnter() { Span span = TRACER.spanBuilder("ServiceManagerDummy.constructor").startSpan(); span.makeCurrent(); System.out.println("构造方法Span已启动: " + span.getSpanContext().getSpanId()); } @Advice.OnMethodExit(onThrowable = Throwable.class) public static void onExit(@Advice.Thrown Throwable throwable) { Span currentSpan = Span.current(); if (throwable != null) { currentSpan.recordException(throwable); } currentSpan.end(); System.out.println("构造方法Span已结束: " + currentSpan.getSpanContext().getSpanId()); } }
内容的提问来源于stack exchange,提问作者Valeriy K.
相关产品推荐
相关产品推荐

