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

如何配置Java版OpenTelemetry将MDC值标记到Span?

将MDC中的客户ID自动添加到所有OTEL Span的解决方案

1. 通过配置自动提取MDC值到Span标签

可以直接通过OTEL配置实现,无需编写代码。OTEL Java SDK支持通过otel.instrumentation.common.mdc.export配置键值对,指定MDC键与对应Span标签名的映射。

比如要把MDC中customerId的值映射为Span的customer.id标签,只需添加以下配置:

otel.instrumentation.common.mdc.export=customerId:customer.id

该配置会让所有自动仪器化生成的Span(如Servlet请求、JDBC调用、HTTP客户端请求等)自动从当前MDC上下文提取指定键的值,添加为Span属性。如果需要映射多个键,用逗号分隔即可:

otel.instrumentation.common.mdc.export=customerId:customer.id,requestId:trace.request.id

2. 通过Servlet过滤器手动注入标签

如果配置方式无法满足需求(比如需要额外逻辑处理),可以在请求入口处添加Servlet过滤器,将MDC中的客户ID注入到OTEL上下文,确保后续所有Span自动继承该标签。

示例代码如下:

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import org.slf4j.MDC;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class CustomerIdOtelFilter implements Filter {
    private static final String MDC_CUSTOMER_KEY = "customerId";
    private static final String SPAN_CUSTOMER_ATTR = "customer.id";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String customerId = MDC.get(MDC_CUSTOMER_KEY);
        if (customerId != null) {
            // 获取当前Span,若不存在则创建根Span(可选)
            Span currentSpan = Span.current();
            currentSpan.setAttribute(SPAN_CUSTOMER_ATTR, customerId);
            
            // 将更新后的Span上下文设为当前,后续所有操作生成的Span都会继承该属性
            Context updatedContext = Context.current().with(currentSpan);
            try (Scope ignored = updatedContext.makeCurrent()) {
                chain.doFilter(request, response);
            }
        } else {
            chain.doFilter(request, response);
        }
    }
}

注意:需确保过滤器在OTEL自带过滤器之前执行,避免无法捕获初始Span。

3. 自定义SpanProcessor全局注入标签

另一种全局方案是实现OTEL的SpanProcessor,在每个Span启动时自动从MDC提取值并添加为属性。这种方式不受请求入口限制,适用于所有生成Span的场景(包括异步任务)。

自定义SpanProcessor实现

import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
import org.slf4j.MDC;

public class MdcCustomerIdSpanProcessor implements SpanProcessor {
    private static final String MDC_CUSTOMER_KEY = "customerId";
    private static final String SPAN_CUSTOMER_ATTR = "customer.id";

    @Override
    public void onStart(Context parentContext, ReadWriteSpan span) {
        String customerId = MDC.get(MDC_CUSTOMER_KEY);
        if (customerId != null) {
            span.setAttribute(SPAN_CUSTOMER_ATTR, customerId);
        }
    }

    @Override
    public boolean isStartRequired() {
        return true;
    }

    @Override
    public void onEnd(ReadWriteSpan span) {}

    @Override
    public boolean isEndRequired() {
        return false;
    }
}

注册SpanProcessor到OTEL TracerProvider

在OTEL初始化阶段,将自定义处理器添加到TracerProvider:

import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;

// 初始化TracerProvider时添加处理器
SdkTracerProviderBuilder tracerBuilder = SdkTracerProvider.builder();
tracerBuilder.addSpanProcessor(new MdcCustomerIdSpanProcessor());
// 其他配置...
SdkTracerProvider tracerProvider = tracerBuilder.build();

内容的提问来源于stack exchange,提问作者James Courtney

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:03:37