
Java Web中日志跟踪的简单实现
一、前言
在编码过程中,常常需要写打印日志语句,我们期望的是同一个业务的日志都在一块,在出问题的时候好根据日志来排查问题。而现实是在应用运行中,日志的输出常常来自不同线程,甚至是在不同微服务中,各种日志记录往往彼此穿插,很难串起来。所以往往在日志中手动增加一些关键字,来对接口的调用链路来进行跟踪。但这种手动增加关键字或唯一标识的做法在微服务场景下,很难在上下游应用的开发人员的编码风格形成统一的规范,并且手动编写也很难称得上优雅。
二、MDC介绍
MDC
(Mapped Diagnostic Context,映射调试上下文)是 log4j
、logback
及log4j2
提供的一种方便在多线程条件下记录日志的功能。MDC
可以看成是一个与当前线程绑定的哈希表,MDC
中包含的内容可以被同一线程中执行的代码所访问。
MDC中的键值对是可以直接被日志框架所使用(即“打印”)的,只需要配置相应日志pattern。例如pattern如下:
代码如下:
此时控制台将输出:
三、实现方案
1、基本思路
修改日志pattern,并在业务开始的时候将trace id放入到MDC,在业务结束时去除MDC的trace id。这样的好处便是代码简洁,不需要手动写trace id,日志风格也能保持统一。
业务开始的时机一般是应用收到HTTP请求,所以可以用Filter或SpringMVC的Interceptor来对MDC中trace id进行初始化和清除。在Dubbo调用的时候也可以通过类似功能的Filter来对MDC中trace id进行操作,从而达到trace id传递的作用。
2、实现(以SpringBoot为例)
2.1 修改log pattern
在SpringBoot中,直接修改application.properties即可:
重点在于%X{TraceId}
,其中TraceId
需要作为key出现在MDC
里。
2.1.2 业务开始
TraceId工具类,封装MDC关于trace id的基础操作:
Filter
方式和Interceptor
二选其一既可,其基本思想是一样的。
Filter方式
Interceptor
2.1.2 业务中使用
正常使用logger,无需关心trace id。例如:
请求该接口将输出如下的日志样式:
四、总结
日志链路的跟踪核心是使用MDC作为trace id载体,在业务开始阶段一般通过拦截器就生成trace id并放入到MDC中,并根据MDC的相关特性将trace id投射到日志文本中,从而实现在同一个业务调用链路中的日志具有唯一标识。
本文转载自公众号:GreatSQL社区
