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

Spring Boot应用中能否将MDC相关内容输出到Tomcat访问日志中

如何将MDC内容添加到Tomcat访问日志

完全可以实现,以下是两种生产环境常用的可行方案:

方案一:Servlet过滤器+Tomcat原生AccessLogValve配置(推荐,侵入性最低)

Tomcat的访问日志组件支持直接读取请求属性字段,你只需要提前把MDC内容转存到请求属性中即可:

  • 第一步:实现全局Servlet过滤器,将需要输出的MDC字段存入请求属性
import org.slf4j.MDC;
import javax.servlet.*;
import java.io.IOException;

public class MDCAccessLogFilter implements Filter {
    // 替换为你实际需要输出的MDC字段列表
    private static final String[] REQUIRED_MDC_FIELDS = {"traceId", "userId", "requestSource"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            // 提前把MDC值存入请求属性,避免后续线程MDC被清空后无法获取
            for (String field : REQUIRED_MDC_FIELDS) {
                Object mdcValue = MDC.get(field);
                if (mdcValue != null) {
                    request.setAttribute("mdc_" + field, mdcValue);
                }
            }
            chain.doFilter(request, response);
        } finally {
            // 请求结束清理请求属性,避免内存泄漏
            for (String field : REQUIRED_MDC_FIELDS) {
                request.removeAttribute("mdc_" + field);
            }
        }
    }
}
  • 第二步:修改Tomcat访问日志格式,读取请求属性
    找到Tomcat conf/server.xml 中Host节点下的AccessLogValve配置,在pattern中添加%{属性名}r格式占位符即可读取对应的请求属性,示例如下:
<Valve className="org.apache.catalina.valves.AccessLogValve"
       directory="logs"
       prefix="localhost_access_log"
       suffix=".log"
       pattern="%h %l %u %t &quot;%r&quot; %s %b %D %{mdc_traceId}r %{mdc_userId}r" />

如果是Spring Boot内嵌Tomcat场景,无需修改xml,直接在配置文件中添加server.tomcat.accesslog.pattern配置,按上述格式添加MDC字段占位符即可。

方案二:自定义AccessLogValve(适合复杂定制场景)

如果需要输出的MDC字段较多,不想逐个配置转存逻辑,可以直接继承Tomcat原生AccessLogValve,重写日志打印逻辑:

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.AccessLogValve;
import org.slf4j.MDC;

public class MDCAwareAccessLogValve extends AccessLogValve {
    @Override
    public void log(Request request, Response response, long time) {
        // 直接在日志打印前从MDC取值,无需提前存请求属性
        String traceId = MDC.get("traceId") == null ? "-" : MDC.get("traceId");
        String userId = MDC.get("userId") == null ? "-" : MDC.get("userId");
        // 自定义日志拼接逻辑,或者把值存入请求属性后调用父类原生log方法
        super.log(request, response, time);
    }
}

配置时把server.xml中AccessLogValve的className替换为你自定义类的全限定名即可。

注意事项

  • 异步请求场景需要额外处理子线程的MDC传递,确保MDC取值操作在请求的父线程中完成
  • 过滤器的优先级需要设置为最高,确保在业务逻辑执行前就完成MDC到请求属性的转存

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:39:04