MDC
1、背景简述
在技术运维过程中,很难从某服务庞杂的日志中,单独找寻出某次 API 调用的全部日志。
为提高排查问题的效率,在多个系统及应用内 根据 统一的 TraceId 查找同一次请求链路上的日志,根据日志快速定位问题,同时需对业务代码无侵入,特别是在高频请求下,也可以方便的搜索此次请求的日志内容。
本此分享一个使用 MDC 实现日志链路跟踪,在微服务环境中,我们经常使用 Skywalking、Spring Cloud Sleut 等去实现整体请求链路的追踪,但是这个整体运维成本高,架构复杂,本次我们来使用 MDC 通过 Log 来实现一个轻量级的会话事务跟踪功能,需要的朋友可以参考一下。
1.1 应用效果图
我们知道了 MDC 的好处后,其实在用户从第一时间调用请求时候,我们其实可以将请求增加 traceid 一并返回,这样用户反馈时候,我们直接用 traceid 就可以全链路追踪到所有请求的情况了,做到信息的闭环。
请求效果图:
LOGBOOK 效果图:
2、关键思路
2.1 MDC
日志追踪目标是每次请求级别的,也就是说同一个接口的每次请求,都应该有不同的 traceId。每次接口请求,都是一个单独的线程,所以自然我们很容易考虑到通过 ThreadLocal 实现上述需求。考虑到 log4j 本身已经提供了类似的功能 MDC,所以直接使用 MDC 进行实现。
关于 MDC 的简述
MDC(Mapped Diagnostic Context)是一个映射,用于存储运行上下文的特定线程的上下文数据。因此,如果使用 log4j 进行日志记录,则每个线程都可以拥有自己的 MDC,该 MDC 对整个线程是全局的。属于该线程的任何代码都可以轻松访问线程的 MDC 中存在的值。
API 说明
clear()=> 移除所有 MDCget(String key)=> 获取当前线程 MDC 中指定 key 的值getContext()=> 获取当前线程 MDC 的 MDCput(String key, Object o)=> 往当前线程的 MDC 中存入指定的键值对remove(String key)=> 删除当前线程 MDC 中指定的键值对
3、目标
- 需要一个全服务唯一的 id,即 traceId,如何保证?
- traceId 如何在服务内部传递?
- traceId 如何在服务间传递?
- traceId 如何在多线程中传递?