首页 游戏 软件 资讯 排行榜 专题
首页
科技数码
MDC+Filter/Interceptor实现用户信息日志追踪:3步解决链路跟踪难题

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

热心网友
55
转载
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。

相关攻略

摩尔线程首届MUSA开发者大会12月20日开幕,硬核技术盛宴来袭
业界动态
摩尔线程首届MUSA开发者大会12月20日开幕,硬核技术盛宴来袭

2025年12月20日至21日,摩尔线程首届MUSA开发者大会(MUSA Developer Conference,简称MDC 2025)将在北京中关村国际创新中心拉开帷幕。作为国内首个聚焦全功能G

热心网友
12.15
MDC+Filter/Interceptor实现用户信息日志追踪:3步解决链路跟踪难题
科技数码
MDC+Filter/Interceptor实现用户信息日志追踪:3步解决链路跟踪难题

本文将详细介绍如何通过Filter​(过滤器) 或 Interceptor​(拦截器) 结合日志框架的MDC机制,实现用户信息的自动注入与日志追踪。 前言在分布式系统或复杂业务系统中,日志是排查问题

热心网友
12.02

最新APP

火柴人传奇
火柴人传奇
动作冒险 04-01
街球艺术
街球艺术
体育竞技 04-01
飞行员模拟
飞行员模拟
休闲益智 04-01
史莱姆农场
史莱姆农场
休闲益智 04-01
绝区零
绝区零
角色扮演 04-01

热门推荐

解限机天袭者滨湾运输中心怎么实战
游戏攻略
解限机天袭者滨湾运输中心怎么实战

解限机天袭者滨湾运输中心实战教学:制霸空中与地形的终极指南 在《解限机》游戏的所有对战地图中,滨湾运输中心无疑是对玩家战术素养与地图掌控力的顶级试炼场。这片区域地形结构极为复杂,高楼耸立,集装箱遍布,形成了无数视野盲区与火力交叉点。若想在滨湾运输中心取得胜利,空有强大机甲与火力是远远不够的,关键在于

热心网友
04.06
Soul聊天记录如何批量删除
手机教程
Soul聊天记录如何批量删除

Soul聊天记录一键清理:批量删除完整步骤与隐私保护技巧 管理社交应用,如同定期整理你的数字家园。随着使用时间增长,Soul中的聊天记录会不断累积,无论是为了释放宝贵的手机存储空间,还是出于对个人隐私安全的重视,掌握批量删除功能都显得尤为必要。本文将为你提供一份清晰、易操作的Soul聊天记录批量删除

热心网友
04.06
GTA6不再延期 开发进入最终收尾阶段
游戏资讯
GTA6不再延期 开发进入最终收尾阶段

知名爆料人Kiwi Talkz近日透露,《GTA6》开发已进入最终收尾阶段,游戏确认不会再次延期。据爆料消息指出,其他游戏厂商要追赶R星在《GTA6》中达成的技术与内容高度,恐需15至20年时间。R星团队在部分技术目标上的规划极具突破性,展现了远超行业当前水准的雄心。 对于持续等待的全球玩家来说,这

热心网友
04.06
鸣潮奥古斯塔怎么培养
游戏攻略
鸣潮奥古斯塔怎么培养

《鸣潮》奥古斯塔养成全攻略:核心材料解析与高效培养路线 若想在《鸣潮》中将强力角色奥古斯塔培养成真正的战场主宰,详尽了解其养成材料是至关重要的第一步。这些资源直接决定了角色从前期成长到后期成型的完整路径,规划是否合理将极大影响实战表现与队伍构建。 首先,系统梳理奥古斯塔所需的各类养成素材是基础。经验

热心网友
04.06
索尼PC移植策略生变 第一方重回独占
游戏资讯
索尼PC移植策略生变 第一方重回独占

索尼工作室悄然修改措辞,PlayStation独占策略或将全面收紧,引发行业热议 近期,游戏行业内部关注到一个值得玩味的现象:索尼互动娱乐旗下多家核心第一方工作室,静悄悄地更新了其官方网站的简介说明。仔细对比可以发现,更新后的措辞发生了微妙但关键的转变——此前涉及PC平台的描述已基本被移除,取而代之

热心网友
04.06