slf4j的MDC功能笔记

前言

记录日志想通用记录一下用户id 请求id之类的参数方便搜索
找了一些资料 发现mdc最合适

参考文档:
https://www.jianshu.com/p/1dea7479eb07
https://logback.qos.ch/xref/chapters/mdc/SimpleMDC.html

示例

  1. 调整log pattern

    1
    2
    # 引用mdc中的mingId变量  %X{变量名称}
    %X{mingId}-%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n
  2. 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.ming;

    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.Test;
    import org.slf4j.MDC;
    import org.springframework.boot.test.context.SpringBootTest;

    import java.util.UUID;

    @SpringBootTest(classes = Start.class)
    @Slf4j
    public class TestSlf4jMDC {
    @Test
    public void test() {
    MDC.put("mingId", UUID.randomUUID().toString());
    log.info("testMingId");
    MDC.clear();
    log.info("testMingIdClean");
    }
    }
  3. 输出日志

    1
    2
    3
    4
    #日期前的就是设置的mingId
    d4b03ec6-bea4-452d-8f47-45c9fd03b1ab-2021-11-25 14:21:15.539 [main] INFO com.ming.TestSlf4jMDC- testMingId
    #当没有mingId 的时候 不显示
    -2021-11-25 14:21:15.539 [main] INFO com.ming.TestSlf4jMDC- testMingIdClean

实际使用方案

filter、Interceptor、aop、都可以使用 配合应用的上下文 可以做到很多日志的打印
mdc就当成一个slf4j自己的一个threadLocal使用就是的

使用filter为日志增加全局requestId
  • pattern

    1
    %X{url}-%X{method}-%X{requestId}:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n
  • filter实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.ming.base.mvc.filter;

    import org.slf4j.MDC;
    import org.springframework.stereotype.Component;

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    import java.util.UUID;

    /**
    * log mdc参数过滤器
    *
    * @author ming
    * @date 2021-11-25 14:35:12
    */
    @Component
    public class LogMdcFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    try {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    MDC.put("requestId", UUID.randomUUID().toString());
    MDC.put("url", request.getRequestURI());
    MDC.put("method", request.getMethod());
    filterChain.doFilter(servletRequest, servletResponse);
    }finally {
    MDC.clear();
    }
    }
    }
  • 接口实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.ming.view;

    import com.ming.base.mvc.annotation.NotNeedLogin;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    @Slf4j
    @NotNeedLogin
    public class LogMdcTestController {

    @GetMapping("/testLog")
    public String testLog() {
    log.debug("测试log");
    log.info("测试log");
    log.warn("测试log");
    log.error("测试log");
    return "测试log";
    }
    }
  • 打印出来的日志

    1
    2
    3
    /testLog-GET-1e4f17f8-31ca-41cf-92c2-83fec76b4eaa:2021-11-25 14:43:49.634 [XNIO-1 task-1] INFO  com.ming.view.LogMdcTestController- 测试log
    /testLog-GET-1e4f17f8-31ca-41cf-92c2-83fec76b4eaa:2021-11-25 14:43:49.634 [XNIO-1 task-1] WARN com.ming.view.LogMdcTestController- 测试log
    /testLog-GET-1e4f17f8-31ca-41cf-92c2-83fec76b4eaa:2021-11-25 14:43:49.634 [XNIO-1 task-1] ERROR com.ming.view.LogMdcTestController- 测试log

总结

mdc 就是slf4j提供的一个 threadLocal
直接使用就是的
很多场景可以使用
例如
记录每次请求的整个链路、
记录某个用户的请求等等
没有zipkin之类链路跟踪工具 用这个mdc 也能简化查询log

------ 本文结束 ------

版权声明
ming创作并维护,博客采用CC协议
本文首发于ming 博客( https://blog.xujiuming.com ),版权所有,转载请注明出处!