Log日志追踪之MDC

779 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

MDC介绍

    MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j、logback 提供的一种方便在多线程条件下记录日志的功能。 MDC 可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。MDC 中包含的内容可以被同一线程中执行的代码所访问。

MDC常用方法

  1. clear() :移除所有MDC日志。

  2. get (String key) :获取当前线程MDC中指定key的值。

  3. getContext() :获取当前线程的MDC。

  4. put(String key, Object o) :往当前线程的MDC中存入指定的键值对。

  5. remove(String key) :删除当前线程MDC中指定的键值对。

MDC应用场景

  1. 记录用户 IP 地址、请求 URL、统计耗时等等,MDC 基本都能支撑;

  2. 用于记录用户的请求到响应整个过程,快速定位生产问题。

  3. 可借助 MDC 去实现链路跟踪。

MDC的使用

记录日志使用时,可在拦截器或者过滤器使用。

这里以SpringBoot中使用为例。

以下为过滤器的部分代码:

public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {

    try {

        // 根据自己的需要,保存相应信息,如用户信息、用户IP
        MDC.put("traceId", request.getHeader("user"));

        filterChain.doFilter(request, response);
    } catch (Exception e) {
        throw e;
    } finally {
        //清理ThreadLocal
        MDC.clear();
    }

}

application.yml配置文件,配置日志文件

logging:
  config: classpath:logback.xml

logback.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">

    <contextName>MDCLog</contextName>

    <!--定义日志文件的存储地址 -->
    <property name="LOG_HOME" value="logs"/>

    <!--定义日志的输出格式 -->
    <property name="PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{traceId}][%X{username}] [%thread] %logger{30}:%line - %msg%n"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %yellow([%X{traceId}][%X{username}]) %highlight(%-5level) %magenta(%logger{30}:%-3L) - %m%n"/>

    <!-- console日志格式 精简版 -->
    <property name="CONSOLE_LOG_PATTERN_SIMPLE"
              value="%d{HH:mm:ss.SSS} %highlight(%-5level) %magenta(%logger{20}:%-3L) - %m%n"/>

    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--encoder 默认配置为PatternLayoutEncoder-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>

    <appender name="RollingFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.log
            </fileNamePattern>
            <maxHistory>180</maxHistory>
            <totalSizeCap>40GB</totalSizeCap>
        </rollingPolicy>
        <!-- 日志文件的格式 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${PATTERN}</pattern>
            <charset>utf-8</charset>
        </encoder>
    </appender>

    <appender name="AsyncRollingFile" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="RollingFile"/>
        <includeCallerData>true</includeCallerData>
    </appender>

    <!-- 输出到控制台和文件,可定义更多的 Appender -->
    <root level="INFO">
        <appender-ref ref="Console"/>
        <appender-ref ref="AsyncRollingFile"/>
    </root>

    <!-- 下面配置一些第三方包的日志过滤级别,用于避免刷屏 -->
    <logger name="org.mybatis" level="INFO"/>
    <logger name="org.springframework" level="WARN"/>
    <logger name="org.apache" level="WARN"/>
    
    <!-- 系统包名 -->
    <logger name="com.project.example" level="DEBUG"/>
    <!--如果需要打印SQL,可以把下面的级别设置为DEBUG -->
    <logger name="com.project.example.dao" level="DEBUG"/>

</configuration>