如何通过OpenTelemetry手动配置实现全方法追踪并过滤不必要内容
手动配置OpenTelemetry实现全方法追踪并过滤不必要内容
要手动实现OpenTelemetry的全方法追踪并过滤不必要内容,核心是复用Java Agent的字节码增强机制,自己实现方法拦截逻辑,而非依赖官方的auto-config agent包。以下是具体实现方案:
1. 引入必要依赖
以Maven项目为例,添加OpenTelemetry核心API、SDK及字节码增强相关依赖:
<dependencies> <!-- OpenTelemetry核心API --> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> <version>1.32.0</version> </dependency> <!-- OpenTelemetry SDK --> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> <version>1.32.0</version> </dependency> <!-- ByteBuddy:用于字节码增强 --> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.14.6</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.14.6</version> </dependency> </dependencies>
2. 实现全方法拦截的Agent
编写一个自定义Java Agent,利用ByteBuddy拦截指定范围内的所有方法,并创建OpenTelemetry Span:
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; import java.lang.instrument.Instrumentation; public class FullTraceAgent { // 初始化Tracer private static final Tracer TRACER = io.opentelemetry.api.OpenTelemetry.getGlobalTracer("custom-full-tracer"); public static void premain(String agentArgs, Instrumentation inst) { new AgentBuilder.Default() // 匹配你需要追踪的根包,替换成自己的应用包路径 .type(ElementMatchers.nameStartsWith("com.your.app")) // 拦截所有非构造、非静态初始化方法 .transform((builder, typeDesc, classLoader, module) -> builder.method(ElementMatchers.not(ElementMatchers.isConstructor()) .and(ElementMatchers.not(ElementMatchers.isTypeInitializer()))) .intercept(MethodDelegation.to(TraceInterceptor.class))) .installOn(inst); } // 方法拦截器 public static class TraceInterceptor { public static Object intercept( @net.bytebuddy.implementation.bind.annotation.Origin java.lang.reflect.Method method, @net.bytebuddy.implementation.bind.annotation.AllArguments Object[] args, @net.bytebuddy.implementation.bind.annotation.This Object target) throws Throwable { // 这里可以先加过滤逻辑,不符合条件直接执行原方法 if (shouldSkip(method)) { return method.invoke(target, args); } // 创建Span,命名格式为「类名.方法名」 Span span = TRACER.spanBuilder(method.getDeclaringClass().getSimpleName() + "." + method.getName()) .startSpan(); try (Scope scope = span.makeCurrent()) { // 执行原方法 return method.invoke(target, args); } catch (Throwable t) { // 记录方法异常 span.recordException(t); throw t; } finally { // 结束Span span.end(); } } // 自定义过滤规则 private static boolean shouldSkip(java.lang.reflect.Method method) { // 示例:跳过所有get开头的方法、工具类的方法 return method.getName().startsWith("get") || method.getDeclaringClass().getSimpleName().equals("StringUtils"); } } }
3. 配置Agent打包
在项目的src/main/resources/META-INF/MANIFEST.MF中指定Premain类:
Manifest-Version: 1.0 Premain-Class: com.your.app.FullTraceAgent Can-Redefine-Classes: true
然后用Maven打包成Agent Jar包。
4. 运行应用并加载Agent
启动应用时,通过JVM参数加载自定义Agent:
java -javaagent:/path/to/your-full-trace-agent.jar -jar your-app.jar
可选:结合OpenTelemetry配置实现更灵活的过滤
除了硬编码过滤规则,还可以通过OpenTelemetry的Sampler或者SpanProcessor实现动态过滤:
- Sampler方式:自定义Sampler,根据Span名称、属性等判断是否采样(即是否保留该Span)
- SpanProcessor方式:添加自定义SpanProcessor,在Span结束前判断是否需要丢弃
示例自定义Sampler:
import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.sdk.trace.samplers.Sampler; import io.opentelemetry.sdk.trace.samplers.SamplingResult; public class FilteringSampler implements Sampler { @Override public SamplingResult shouldSample(SamplingContext context) { String spanName = context.getSpanName(); // 跳过get开头的Span if (spanName.startsWith("get")) { return SamplingResult.DROP; } return SamplingResult.RECORD_AND_SAMPLE; } @Override public String getDescription() { return "FilteringSampler"; } }
然后在初始化OpenTelemetry SDK时配置这个Sampler:
OpenTelemetrySdk.builder() .setTracerProvider(TracerProvider.builder() .setSampler(new FilteringSampler()) .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) .build()) .buildAndRegisterGlobal();
注意事项
- 字节码增强会带来一定性能损耗,务必精准控制追踪范围,避免拦截JDK核心类或无意义的工具方法
- 确保OpenTelemetry SDK已正确初始化,包括配置Span导出器(如Otlp、Jaeger等),否则生成的Span无法被收集
- 如果是Spring Boot应用,也可以用Spring AOP实现方法拦截,但字节码增强方式更通用,不受框架限制
内容的提问来源于stack exchange,提问作者Valeriy K.
相关产品推荐
相关产品推荐

