写在前面
作为后端开发,相信大家每天都会时不时的和日志打交道,日志不仅是我们排查bug的重要手段,同时也可以作为监控、分析场景下的重要依据。SLF4J作为当下日志框架标准,相信大家都已经很熟悉了。如果大家搞不清楚slf4j、log4j2、logpack的关系,可以看我的这一篇文章:log4j2、logback、slf4j傻傻分不清楚
不知道大家在工作中有没有遇到下面的场景:多线程的任务调度中,我同时跑了多个任务让线程池去执行,但其中一个任务失败了,我想针对性的查看这个任务的日志来排查问题,也就是日志链路追踪问题。这里大家或许会想到分布式链路追踪,但是它的实现有些复杂,今天我们讨论的是一个非常简单的实现–SLF4J MDC。
一、简介
MDC全称Mapped Diagnostic Contexts,本质是一个map,目的是为了解决多线程下的日志链路追问题。SLF4J为我们封装了MDC,也就是只要使用SLF4J就可以无缝对接MDC。
二、使用
相信大家对logback、log4j2的日志配置格式已经很熟悉了,我们不再赘述。引入MDC大致分为以下三步:
- 配置properties或xml文件。
- 编写日志工具类。
- 在需要打印日志的地方,调用工具方法。
不管是使用logback还是log4j2,配置MDC的原理是一样的,我们以logback为例进行介绍。
场景:一个任务的执行包括任务的定义和任务实例的生成和执行,一个任务的执行链路追踪需要我们在日志中记录。操作如下:
1. 修改配置文件
<pattern>
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS} %logger{96} [%thread]:[%line] - TaskDefine-%X{taskDefineId:-0} - %msg%n
</pattern>
添加 [TaskDefine-%X{taskDefineId:-0}] [TaskInstance-%X{taskInstanceId:-0}] 配置,%X可以理解为自定义的占位符,只为MDC提供服务。taskDefineId和taskInstanceId会被MDC的value值替换,如果值为空,默认值为0。
2. 编写日志工具类
public class LoggerUtils {
public static final String TASK_DEFINE_ID_MDC_KEY = "taskDefineId";