当前位置: 首页
科技数码
MDC+Filter/Interceptor实现用户信息日志追踪:3步解决链路跟踪难题

MDC+Filter/Interceptor实现用户信息日志追踪:3步解决链路跟踪难题

热心网友 时间:2025-12-02
转载

本文将通过Filter(过滤器)和Interceptor(拦截器)结合日志框架的MDC机制,详细讲解如何自动注入用户信息并实现全链路日志跟踪。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

前言

在分布式系统或复杂业务架构中,日志是排查问题、追踪流程的关键工具。然而系统默认的日志输出往往缺少用户维度信息,导致问题发生时难以快速定位具体用户的操作链路。下面将详细介绍如何利用Filter或Interceptor与日志框架的MDC协作,实现用户信息的自动注入与全链路跟踪。

原理解析

要实现用户信息追踪,首先需要理解三个核心技术组件的作用与协作逻辑:MDC、Filter和Interceptor。

MDC:日志上下文的存储容器

MDC是SLF4J及Logback、Log4j2等日志框架提供的上下文工具,本质上是通过ThreadLocal实现的线程级键值对存储容器。其核心功能包括:

在请求处理线程中保存临时上下文信息(如用户ID、用户名、请求ID等);日志输出时自动从MDC提取配置的键值,无需在每处日志打印代码中手动传入用户信息;线程结束后自动清理上下文,避免内存泄漏(需手动确保清理逻辑)。

MDC核心API(以SLF4J为例):

// 向MDC存入键值对(如用户ID)
MDC.put("userId", "user_123456");
// 从MDC获取值
String userId = MDC.get("userId");
// 清空当前线程的MDC上下文(关键,必须执行)
MDC.clear();
Filter与Interceptor:请求链路的拦截器

图片图片

图片

Filter和Interceptor都用于拦截HTTP请求,在处理前后执行自定义逻辑(如权限校验、参数预处理),这是注入MDC上下文的最佳切入点。

实践方案

方案1:基于Filter+MDC实现

自定义MDC过滤器
/**
 * 基于Filter的MDC用户信息注入过滤器
 */
public class MdcUserFilter extends OncePerRequestFilter {
    // 定义MDC中用户信息的键(需与日志配置一致)
    private static final String MDC_USER_ID = "userId";
    private static final String MDC_USER_NAME = "userName";
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try {
            // 1.从请求头提取用户信息(实际项目需替换为Token解析、Session获取等逻辑)
            String userId = request.getHeader("X-User-Id");
            String userName = request.getHeader("X-User-Name");
            
            // 2.注入MDC(若用户未登录,可存入默认值如"unknown")
            MDC.put(MDC_USER_ID, userId != null ? userId : "unknown");
            MDC.put(MDC_USER_NAME, userName != null ? userName : "unknown");
            
            // 3.继续执行请求链路(进入Controller层)
            filterChain.doFilter(request, response);
        } finally {
            // 4.关键:请求结束后清理MDC,避免线程复用导致上下文污染(线程池场景必做)
            MDC.clear();
        }
    }
}
步骤2:注册Filter到Spring容器
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean mdcUserFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MdcUserFilter());
        // 拦截所有请求
        registrationBean.addUrlPatterns("/*");
        // 设置过滤器优先级(值越小优先级越高,确保先于其他业务过滤器执行)
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
}

方案2:基于Interceptor+MDC实现

步骤1:自定义MDC拦截器
/**
 * 基于Interceptor的MDC用户信息注入拦截器
 */
public class MdcUserInterceptor implements HandlerInterceptor {
    private static final String MDC_USER_ID = "userId";
    private static final String MDC_USER_NAME = "userName";
    
    /**
     * 请求处理前执行:注入MDC
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.提取用户信息(逻辑与Filter一致,可复用工具类)
        String userId = request.getHeader("X-User-Id");
        String userName = request.getHeader("X-User-Name");
        
        // 2.注入MDC
        MDC.put(MDC_USER_ID, userId != null ? userId : "unknown");
        MDC.put(MDC_USER_NAME, userName != null ? userName : "unknown");
        
        // 返回true:继续执行后续链路(如Controller)
        returntrue;
    }
    
    /**
     * 请求完成后执行(无论是否抛异常):清理MDC
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 关键:清理MDC,避免线程池上下文污染
        MDC.clear();
    }
}
步骤2:注册Interceptor到SpringMVC
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MdcUserInterceptor())
                // 拦截所有请求
                .addPathPatterns("/**")
                // 排除无需拦截的路径(如登录接口、静态资源等)
                .excludePathPatterns("/api/login", "/static/**", "/error");
    }
}

配置日志输出MDC信息

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - userId:%X{userId} userName:%X{userName} - %msg%n UTF-8 logs/app.log logs/app.%d{yyyy-MM-dd}.log 30 %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - userId:%X{userId} userName:%X{userName} - %msg%n UTF-8

线程池场景下的MDC传递

手动传递MDC上下文
public class AsyncMdcDemo {
    // 初始化线程池
    private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
    public void doAsyncTask() {
        // 1.获取当前线程的MDC上下文(包含用户信息)
        Map mdcContext = MDC.getCopyOfContextMap();
        
        // 2.提交异步任务到线程池
        executorService.submit(() -> {
            try {
                // 3.子线程中注入MDC上下文
                if (mdcContext != null) {
                    MDC.setContextMap(mdcContext);
                }
                
                // 4.异步业务逻辑(日志会自动包含用户信息)
                log.info("执行异步任务:处理用户订单");
            } finally {
                // 5.子线程结束后清理MDC
                MDC.clear();
            }
        });
    }
}
封装线程池(避免重复代码)

// Spring异步任务装饰器:自动传递MDC public class MdcTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { // 获取当前线程MDC上下文 Map mdcContext = MDC.getCopyOfContextMap(); return () -> { try { // 子线程注入MDC if (mdcContext != null) { MDC.setContextMap(mdcContext); } runnable.run(); } finally { MDC.clear(); } }; } } // 配置Spring异步线程池(使用装饰器) @Configuration @EnableAsync public class AsyncConfig { @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); // 设置MDC装饰器 executor.setTaskDecorator(new MdcTaskDecorator()); executor.initialize(); return executor; } }

总结

通过Filter/Interceptor与MDC机制实现用户信息追踪,核心在于拦截请求→注入上下文→日志输出→清理上下文的闭环流程。其价值主要体现在:

无侵入式:无需在业务代码中手动传递用户信息到日志,降低开发成本;可追溯性:日志自动关联用户维度,快速定位单个用户的操作链路;灵活性:支持全局或局部拦截,适配不同业务场景。

来源:https://www.51cto.com/article/825459.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
微星 2026 款泰坦 18 Max 游戏本国行上市:7 热管 2 风扇,整机双烤 260W

微星 2026 款泰坦 18 Max 游戏本国行上市:7 热管 2 风扇,整机双烤 260W

微星泰坦 18 Max 2026款国行发布:极致双烤260W性能,散热系统全面解析 对于追求极致性能的游戏玩家和专业创作者而言,顶级游戏本市场迎来了一个重磅选项。近日,微星正式在国内推出了其旗舰级新品——2026款泰坦 18 Max(Raider 18 Max HX)游戏笔记本电脑,旨在重新定义高性

时间:2026-04-06 07:03
旗舰配置 25000Pa 吸力 + 95℃ 自清洁:石头 A30 CE 洗地机 1278 元免费用 15 天

旗舰配置 25000Pa 吸力 + 95℃ 自清洁:石头 A30 CE 洗地机 1278 元免费用 15 天

京东百亿补贴开启:石头 A30 CE 系列洗地机享“买贵双倍赔”与“15天免费试用” 如果您正在关注高品质清洁电器,那么现在有一个不容错过的限时机会。石头科技旗下的 A30 CE 系列智能洗地机现已加入“京东百亿补贴”专场。本次促销不仅带来极具竞争力的价格,更提供了两大核心保障:一是“买贵双倍赔”的

时间:2026-04-06 07:02
比官方预告时间更早:消息称“超级小爱”PC 客户端正推送给小米笔记本 Pro 14

比官方预告时间更早:消息称“超级小爱”PC 客户端正推送给小米笔记本 Pro 14

比官方预告时间更早:消息称“超级小爱”PC 客户端正推送给小米笔记本 Pro 14 四月份伊始,小米在AI落地应用方面便带来了令人惊喜的新进展。据知名数码博主@懒酱的日记本透露,备受期待的“超级小爱”PC客户端已开始向小米笔记本 Pro 14用户推送。此次推送的时间点,较官方之前公布的四月中旬计划明

时间:2026-04-06 07:01
红魔姜超“冒险爆料”:Pad 新品不是四月就是五月发布,一定不让大家失望

红魔姜超“冒险爆料”:Pad 新品不是四月就是五月发布,一定不让大家失望

红魔姜超透露:全新游戏平板将于四月或五月发布,承诺带来惊艳体验 游戏硬件领域即将迎来重磅更新。努比亚红魔游戏手机的产品线负责人姜超,近日通过社交媒体进行了一次颇具悬念的“前瞻剧透”,成功引发了广大游戏玩家和科技爱好者的高度关注。他明确指出,红魔全新一代游戏平板的发布日期已锁定在四月或五月,并使用了“

时间:2026-04-05 22:56
未来人类 X98W 移动“工作站”笔记本电脑上线官网,4 月内发售

未来人类 X98W 移动“工作站”笔记本电脑上线官网,4 月内发售

未来人类X98W移动工作站正式发布:重新定义移动端专业性能的新标杆 在专业移动计算领域,总有一些产品能够打破常规认知。近日,未来人类(TerransForce)正式在其官网上线了全新的X98W高性能移动工作站,并宣布将于本月内全面发售。这款设备的问世,无疑为那些在移动办公环境中仍需要桌面级别强悍性能

时间:2026-04-05 22:54
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程