欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Springboot-MDC+logback实现日志追踪

程序员文章站 2022-03-01 12:40:08
...

一、MDC介绍

        MDC(Mapped Diagnostic Contexts)映射诊断上下文,该特征是logback提供的一种方便在多线程条件下的记录日志的功能。
        某些应用程序采用多线程的方式来处理多个用户的请求。在一个用户的使用过程中,可能有多个不同的线程来进行处理。典型的例子是 Web 应用服务器。当用户访问某个页面时,应用服务器可能会创建一个新的线程来处理该请求,也可能从线程池中复用已有的线程。在一个用户的会话存续期间,可能有多个线程处理过该用户的请求。这使得比较难以区分不同用户所对应的日志。当需要追踪某个用户在系统中的相关日志记录时,就会变得很麻烦。
        MDC正是用于解决上述问题的,MDC 可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。

二、MDC实现日志跟踪

        一个系统提供服务,提供给其他系统来调用,当其他系统调用的时候,请求头带上唯一的请求标识(requestId),把这个requestId输出到日志中,这样两个系统直接就会形成一个执行链,用requestId串联起来,当出现错误时,可以在调用方查询对应的请求日志,也可以在服务方查询请求日志,定位问题很方便,输出日志的地方很多。可以使用MDC配合logback中的pattern。

三、HandlerInterceptor拦截器

相关介绍:

SpringBoot使用过滤器、拦截器、切面(AOP),及其之间的区别和执行顺序 - 劈天造陆 - 博客园
HandlerInterceptor_dekulugu的博客-CSDN博客_handlerinterceptor

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //添加MDC日志
        String appkey = request.getHeader("appkey");
        MDC.put("LOG_TRACK_ID", appkey);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        //移除MDC日志
        MDC.remove("LOG_TRACK_ID");
    }

}

四、logback文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="logLevel" value="INFO"></property>
    <property name="logPath" value="./logs"></property>
    <property name="maxHistory" value="31"/>
    <property name="maxFileSize" value="100MB"/>
    <property name="totalSizeCap" value="200GB"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] [%X{logTrackId}] %-5level %logger{35} - %msg %n</pattern>
        </encoder>
    </appender>

    <appender name="FILE_INFO" class="ch.qos.logback.classic.sift.SiftingAppender">
        <!--discriminator鉴别器,根据logTrackId这个key对应的value鉴别日志事件,然后委托给具体appender写日志-->
        <discriminator>
            <key>logTrackId</key>
            <defaultValue>default</defaultValue>
        </discriminator>
        <sift>
            <!--具体的写日志appender,每一个logTrackId创建一个文件-->
            <appender name="FILE-${logTrackId}" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <!--直接指定文件路径-->
                <append>true</append>
                <encoder charset="UTF-8">
                    <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] [%X{logTrackId}] %-5level %logger{35} - %msg%n</pattern>
                </encoder>
                <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                    <!--定义文件滚动时的文件名的格式-->
                    <fileNamePattern>${logPath}/%d{yyyy-MM-dd}/${logTrackId}-%i.log</fileNamePattern>
                    <maxHistory>${maxHistory}</maxHistory>
                    <maxFileSize>${maxFileSize}</maxFileSize>
                    <totalSizeCap>${totalSizeCap}</totalSizeCap>
                </rollingPolicy>
                <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                    <level>INFO</level>
                </filter>
            </appender>
        </sift>
    </appender>

    <!-- 异步输出 -->
    <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE_INFO"/>
    </appender>

    <root level="${logLevel}">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE_INFO"/>
    </root>
</configuration>

相关学习链接:

logback新认识(二):logback之MDC日志跟踪、日志自定义效果_IT-CRUD-CSDN博客

【日志追踪】(微服务应用和单体应用)-logback中的MDC机制 - 听风是雨 - 博客园

https://www.136.la/jingpin/show-86154.html