MDC(Mapped Diagnostic Context)诊断上下文映射,是slf4j提供的一个支持动态打印日志信息的工具,举例来说,对于一个web Server,如果服务端想在打印出的每行日志中都记录客户端的ip,你只需要在服务端入口获取到cleint ip,设置到MDC中,服务请求结束时,移除掉。如果日志配置文件配置得当,这一过程中所有打印的日志信息中都会显示clientIp。
使用方式
见logback中的MDC一文即可,比较简单。
在大型分布式系统中,MDC的用途是很大的。阿里巴巴的大量业务系统服务端记录日志都使用到了这一技术,所有业务请求在中间件(鹰眼)的作用下,都会带上一个traceId,业务系统中打印日志时需要将该traceId记录下来,分析问题、联调都会带来很大便利。
一个需要注意的点就是,MDC是线程安全、隔离的,如果服务端处理请求的线程需要生产更多的子线程时(Executors.execute), MDC中的信息会丢失,开发者需要自己主动拷贝 MDC信息到子线程中去,相关的api有MDC.getCopyOfContextMap()
,MDC.setContextMapValues()
原理
涉及到SPI原理, Adapter适配器设计模式,ThreadLocal线程副本变量等方面。
slf4j-api的MDC工具类可以put(key,val),看代码可以发现,是通过SLF4JServiceProvider
找到了绑定的底层日志框架,获取到了底层真正的MDCAdapter
, put方法也是底层的MDCAdapter
在执行。
MDC目前只有log4j和logback有实现,logback的实现类LogbackMDCAdapter利用的ThreadLocal技术保证了每个请求线程保有自己的MDC环境变量。
其实,不难猜,当打印日志时,肯定会根据配置文件中MDC的配置符 去MDC中获取到相应的MDC值,替代日志格式中的占位符,这里不详细展开,只附加一张图。