Log日志的实现原理

log.info(" XXX");

打印日志的时候,Log组件会将“写入”动作封装成一个LogEvent事件,而这个事件的具体表现形式由Log Format和MDC共同控制,Format决定了Log的输出格式,而MDC决定了输出什么内容。

LogFormat 

Log组件定义了日志输出格式,这和我们平时使用“String.format”的方式差不多,集成了Sleuth后的Log输出格式是下面这个样子

"%5p [sleuth-traceA,%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]"

MDC

MDC是通过InheritableThreadLocal来实现的,它可以携带当前线程的上下文信息。它的底层是一个Map结构,存储了一系列Key-Value的值。

SpringCloudd的Sleuth就是借助Spring的AOP机制,在方法调用的时候配置了切面,将链路追踪数据加入到了MDC中,这样在打印Log的时候,就能从MDC中获取这些值,

填入到Log Format中的占位符里。

由于MDC基于InheritableThreadLocal而不是ThreadLocal实现,因此假如在当前线程中又开启了新的子线程,那么子线程依然会保留父线程的上下文信息。

 

 InheritableThreadLocal和ThreadLocal相比,可以获取父类的值。重写了getMap、createMap方法。

 

源码学习

源码可以参考logback组件中LogEvent类的prepareForDeferredProcessing方法,了解MDC和Log Format是如何工作的。可以在打印log的地方打一个断点,本地启动项目后发起一次调用,然后一路跟进去。

/**应在序列化事件之前调用此方法。在使用异步或延迟日志记录时也应该调用它。
请注意,由于性能问题,此方法不提取调用方数据。提取呼叫者信息是呼叫者的责任。
**/
public void prepareForDeferredProcessing() {
    this.getFormattedMessage();
    this.getThreadName();
    // fixes http://jira.qos.ch/browse/LBCLASSIC-104
    this.getMDCPropertyMap();
}

 

posted @ 2023-07-30 22:03  CodingOneTheWay  阅读(100)  评论(0编辑  收藏  举报
回到顶部