You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:45:36