使用MDC为Logback slf4 日志记录线程ID,区分每次执行的会话日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/catoop/article/details/71713232 我们先回想这样一个场景: 在Java开发中,因为业务需求肯定会输出很多日志。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/catoop/article/details/71713232

我们先回想这样一个场景:
在Java开发中,因为业务需求肯定会输出很多日志。在出现问题时,根据输出的日志分析问题。
对于一个访问量很大的网站来说,日志的输出速度是很快的,同样的代码方法被同时调用是很正常的。
那么现在问题来了,我们如何从日志中来区分每一个会话的日志呢?就是我们发现了一个异常,如何知道在这个异常之前对应的一些列日志是什么呢?

我们都知道,不管是普通后台代码执行(定时任务这种)还是用户的HTTP请求,系统都会为开启每一个独立的线程来执行。
意思就是:10个用户瞬间同时访问了同一个请求,那么Tomcat就会分配10个不同的线程来分别执行每个请求。

思路来了:我们只需要在输出日志的时候,将每个线程的ID同时输出出来即可。这样我们首先要保证每个线程的ID是唯一的。logback日志本身就支持输出线程名称,使用这个是不行的,因为现在都是线程池,同一个线程是会被不同时间的多次请求公用的。
sl4j 提供的一个工具类MDC,支持 logback和log4j,其作用就是可以让你放入一些变量值到日志中并输出。

下面看一下片段代码:
在线程执行第一行代码之前放入变量值

MDC.put("ThreadID", java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());

然后在 (以logback为例) 中使用通配符就可以输出这个值,配置片段如下:
注意留意其中的 {ThreadID}

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                %d|%thread|%X{ThreadID}|%-5level|%logger{65}|%msg%n
            </pattern>
        </encoder>

现在又有一个问题,如何让线程在执行第一行(相对)代码的时候使用 MDC.put 加入变量值呢?
使用 Filter、MVC 拦截器(Interceptor)。
特别注意:在开始的地方加入ID,同样需要在线程结束的时候删除该ID,因为线程在线程池里,如果不在执行完业务代码后删除ThreadID,那么该线程下次被使用的时候ThreadID还是存在的,就达不到我们预期的效果了。

不多说了,下面给出实例代码:
我没有使用Filter,使用的是HandlerInterceptor,道理一样的。因为我嫌Filter 拦截范围太大,什么都拦截还要自己判断处理(这个根据自己实际需求选择吧)。

/**
 * 日志拦截器
 */
public class LogInterceptor implements HandlerInterceptor {

    /**
     * 会话ID
     */
    private final static String SESSION_TOKEN_KEY = "sessionTokenId";

    private static final transient Logger logger = LoggerFactory.getLogger(LogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 放SessionId
        String token = java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        MDC. put(SESSION_TOKEN_KEY, token);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 其他逻辑代码

        // 最后执行MDC删除
        MDC. remove(SESSION_TOKEN_KEY);
    }
}

logback.xml 配置文件中的部分代码,仅供参考。

    <appender name="front"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logger.basedir}/front.log</file>
        <rollingPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logger.basedir}/front.%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                %d|%thread|%X{sessionTokenId}|%-5level|%logger{65}|%msg%n
            </pattern>
        </encoder>

        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
    </appender>

logback 还内置了过滤器,比如 MDCInsertingServletFilter,说了这么多都不如直接看官网资料,官网地址:https://logback.qos.ch/manual/mdc.html#autoMDC

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
3月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
946 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
3月前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
136 5
|
4月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
474 3
|
2月前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
64 2
|
3月前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
76 1
|
4月前
|
存储 Java Android开发
Android|记一个导致 logback 无法输出日志的问题
在给一个 Android 项目添加 logback 日志框架时,遇到一个导致无法正常输出日志的问题,这里记录一下。
79 2
|
4月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
196 1
|
6月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
|
2月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
11天前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log