logback源码解读笔记(springboot)

最近在学习使用同事开发的日志框架,感觉对于logback除了基本的使用并没有很深刻的了解,遂对debug过程做大概记录以备忘,debug所用demo如下:https://gitee.com/eshin/logbackDemo

一、Logfactory初始化

LogFactory在初次getLogger的时候完成初始化,之后的每次调用都是从缓存中读取
eg:private static final Log logger = LogFactory.getLog(SpringApplication.class); springboot 在main方法没有getlogger的情况下在org.springframework.boot.SpringApplication初次调用org.apache.commons.logging.LogFactory.getLog(Class):默认初始化的Factory为org.apache.commons.logging.impl.SLF4JLogFactory.SLF4JLogFactory()-------------》org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(String)

image.png
------------------》org.slf4j.LoggerFactory.getLogger(String)(可直接调用此处获取logger)---------------------》org.slf4j.LoggerFactory.getILoggerFactory()
image.png
--------------》org.slf4j.LoggerFactory.performInitialization()------》org.slf4j.LoggerFactory.bind()
image.png

完成StaticLoggerBinder的初始化后,将标志位INITIALLZATION_STATE置为3,在下次调用是直接获取单例不用再进行初始化操作,INITIALLZATION_STATE为volatile修饰的静态变量,保证了多线程环境的可见性,但无法保证binder的单例只有一次加载,binder的单例由StaticLoggerBinder设计完成。

StaticLoggerBinder的初始化
image.png

1、LoggerContext defaultLoggerContext = new LoggerContext();
image.png

2、org.slf4j.impl.StaticLoggerBinder.init()

  • 2.1 new ContextInitializer(defaultLoggerContext).autoConfig();
    image.png
    ch.qos.logback.classic.util.ContextInitializer.findURLOfDefaultConfigurationFile(boolean)在类路径下查找logback.groovy ,logback.xml ,logback-test.xml查找这三个文件,若能找到这三个文件,则通过这三个配置文件生成Configurator,否则生成默认的ch.qos.logback.classic.BasicConfigurator。
  • 2.2 contextSelectorBinder.init(defaultLoggerContext, KEY);
    image.png

    至此,LogFactory初始化完成、org.slf4j.LoggerFactory.getLogger(String)便可获取logger。


二、springboot与logback整合

spring-boot.x.x.x.jar的spring.factories文件中

image.png
org.springframework.boot.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent)------------》org.springframework.boot.logging.LoggingApplicationListener.initialize(ConfigurableEnvironment, ClassLoader)在监听到ApplicationEnvironmentPreparedEvent事件后进入initialize方法。-------------》org.springframework.boot.logging.LoggingApplicationListener.initializeSystem(ConfigurableEnvironment, LoggingSystem, LogFile)
image.png
----------------------》org.springframework.boot.logging.logback.LogbackLoggingSystem.initialize(LoggingInitializationContext, String, LogFile) ** 此时configLocation为空 **
image.png
---------------------》由于configLocation为空 -----------》org.springframework.boot.logging.AbstractLoggingSystem.initialize(LoggingInitializationContext, String, LogFile)------------》org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(LoggingInitializationContext, LogFile)-----------》
image.png

  • 1、加载配置文件 -----------》org.springframework.boot.logging.logback.LogbackLoggingSystem.loadConfiguration(LoggingInitializationContext, String, LogFile)-----------》
    image.png
  • 1.1、根据logback配置文件加载context(logback-spring.xml)

    org.springframework.boot.logging.logback.LogbackLoggingSystem.configureByResourceUrl(LoggingInitializationContext, LoggerContext, URL)-------------->ch.qos.logback.core.joran.GenericConfigurator.doConfigure(URL)-------------->ch.qos.logback.core.joran.GenericConfigurator.doConfigure(InputStream, String)--------->ch.qos.logback.core.joran.GenericConfigurator.doConfigure(InputSource)这个过程将配置文件解析成recorder.recordEvents(inputSource) recordEvents是xml的每个标签,分startEvent、bodyEvent和endEvent对应标签头,内容标签,和标签尾
    image.png
    image.png
  • 1.1.1buildInterpreter();该方法主要完成设置RuleStore
    ch.qos.logback.core.joran.GenericConfigurator.buildInterpreter()-------------->
    主要的RuleStore在如下两个类中设置分别设置不同包下的action
    ch.qos.logback.classic.joran.JoranConfigurator(ch.qos.logback.classic.joran.action
    ch.qos.logback.core.joran.JoranConfiguratorBase<E>(ch.qos.logback.core.joran.action
    设置的rule供解析event对应的标签action使用
    image.png
    image.png
  • 1.1.2----------------->ch.qos.logback.core.joran.spi.EventPlayer.play(List<SaxEvent>)
    image.png

    ---------------->ch.qos.logback.core.joran.spi.nterpreter.startElement(StartEvent)----------------->ch.qos.logback.core.joran.spi.Interpreter.startElement(String, String, String, Attributes)--------------------->
    image.png
    image.png

    主要的几个action的功能:
  • ch.qos.logback.classic.joran.action.ConfigurationAction
    image.png
    当debug=true(默认)时创建OnConsoleStatusListener实例并启动,用于控制台打印status(logcontext中的BasicStatusManager中保存的ch.qos.logback.core.status.Status对象)启动之后,当有调用ch.qos.logback.core.BasicStatusManager.add(Status)时,控制台便打印当前add的status。-------------》ch.qos.logback.core.BasicStatusManager.fireStatusAddEvent(Status)此处遍历Listener,之中包括该Listener。
  • ch.qos.logback.core.joran.action.IncludeAction

    image.png
    将logback-spring.xml中include标签指定的xml配置文件加载并加入WatchList,然后与logback-spring.xml文件一样处理成recordEvents,并加入到加载logback-spring.xml时生成的record(recorder.saxEventList)中。

  • ch.qos.logback.core.joran.action.ConversionRuleAction

    image.png
    image.png
    用于初始化converter
    conversionWord的值就是配置pattern时需要匹配成对应值的key,如下
    image.png
    image.png
    当converter匹配到对应的key便转换成需要打印的日志内容,因此,可自定义converter及pattern关键字实现更灵活的日志打印

  • ch.qos.logback.core.joran.action.PropertyAction

    image.png
    用于存储properties,默认scope为local,存在InterpretationContext中,当scope为context时,存在logContext中,为system时存为系统变量

  • ch.qos.logback.core.joran.action.AppenderAction<E>

    image.png
    image.png
    完成appender的初始化,ch.qos.logback.core.rolling.RollingFileAppender<E>,该appender设置rollingPolicy,调用start()方法时会检测rollingPolicy是否生效以及需要的日志文件是否存在,若不存在便根据在rollingpolicy设置的pattern新建一个。
    在打印日志调用ch.qos.logback.core.rolling.RollingFileAppender.subAppend(E)时,会先调用判断是否需要分割文件(打印日志步骤)
    image.png
    当有子标签时需要其他的action完成配置和引用,如:ch.qos.logback.core.joran.action.NestedComplexPropertyIA完成对rollingPolicy,encoder,等的加载,当仍有子标签时,按同样的方式遍历event加载。bodyevent直接设置值。
    NestedComplexPropertyIA加载时,当有配置class则根据class加载实例(rollingPolicy),若没有配置class,则按标签名为规则去查找(encoder)在之前的步骤中,
    image.png
    配置了默认的encoder,layout,和evalator,因此也可以根据需要自定义需要的encoder等,并通过配置class的方式配置,
    通过NestedComplexPropertyIA加载的startEvent,其对应的endevent将进入ch.qos.logback.core.joran.action.NestedComplexPropertyIA.end(InterpretationContext, String)
    rollingPolicy,调用ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy<E>.start()方法完成rollingPolicy的加载。
    完成对文件名pattern的设置解析。
    encoder,主要是调用ch.qos.logback.classic.encoder.PatternLayoutEncoder.start()方法完成encoder的加载。
    image.png
    image.png

  • 1、ch.qos.logback.core.pattern.PatternLayoutBase.getEffectiveConverterMap()
    image.png

    p.compile();方法会将与patter的关键字匹配的converter保留,其余的过滤掉

  • 2、start方法主要完成converter的一些初始化工作,设置context,key,以便调用convert方法的时候进行内容转换。
    image.png

    当appender的类型是AsyncAppender时,在ch.qos.logback.core.joran.action.AppenderAction.end(InterpretationContext, String)时,ch.qos.logback.core.AsyncAppenderBase.start()会启动一个异步worker,对日志event进行异步打印处理。
    image.png
  • ch.qos.logback.classic.joran.action.LoggerAction

    image.png
    为指定的包和类定义logger对象,并设置日志级别当logger带有appender-ref子标签时,继续startEvent并执行到ch.qos.logback.core.joran.action.AppenderRefAction<E>完成appender的引用

  • org.springframework.boot.logging.logback.SpringPropertyAction

    image.png
    配置需要的变量,当spring配置文件中有对应的值时取spring中配置文件的内容,否则使用defaultValue的值
    (application.properties的加载在加载logback-spring.xml之前,其实在LogFactory初始化的时候有过一次对logback配置文件的加载(如果存在的话,只不过在加载logback-spring.xml时重置了))

  • ch.qos.logback.core.joran.action.NewRuleAction
    自定义标签,需要通过改action解析自定义标签对应action的class。因此,该标签的配置,需要在使用该自定义标签之前配置。

    image.png
    查找action时,key是拼接上所有的父节点如[configuration][myrule]、[configuration][appender][encorder]
    因此自定义action时,需要用“/”将父节点分隔开,向rulestore存储action时会将pattern configuration/myrule 解析成[configuration][myrule]
    image.png
    还有其他action由于尚未使用,未曾了解。
    当所有的event执行完之后,便完成了对logback配置文件的加载

三、logger的执行与日志的打印

在完成LogFactory的加载后,就可以通过factory获取logger,当logger执行info(),debug(),warn(),error(),方法,将会执行到
ch.qos.logback.classic.Logger.filterAndLog_1(String, Marker, Level, String, Object, Throwable)或者
ch.qos.logback.classic.Logger.filterAndLog_2(String, Marker, Level, String, Object, Object, Throwable)或者
ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(String, Marker, Level, String, Object[], Throwable)
三者的不同之处在于通过“{}”占位符可填充的参数个数不同。三者最终调用的都是
ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(String, Marker, Level, String, Object[], Throwable)

------------------->ch.qos.logback.classic.Logger.callAppenders(ILoggingEvent)
image.png
image.png
------------------>ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(E)
image.png
AsyncAppender主要完成将日志event放入ch.qos.logback.core.AsyncAppenderBase<E>的blockingQueue中,供二中开启的worker消费。
image.png
ConsoleAppender主要完成将日志event在控制台输出
RollingAppender的实例在进入ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(E)之后调用this.append(eventObject);------------》ch.qos.logback.core.OutputStreamAppender.append(E)-------------》ch.qos.logback.core.rolling.RollingFileAppender.subAppend(E)此时调用rollingPOlicy----》ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP.isTriggeringEvent(File, E)
image.png
最终,这三个appender调用的super.subAppend(event)都指向----------------》ch.qos.logback.core.OutputStreamAppender.subAppend(E)--------------》ch.qos.logback.core.OutputStreamAppender.writeOut(E)-------------》调用ch.qos.logback.classic.encoder.PatternLayoutEncoder的doEncode方法,实际调用---》ch.qos.logback.core.encoder.LayoutWrappingEncoder.doEncode(E)
image.png
  • 1、layout.doLayout(event);-------------》ch.qos.logback.classic.PatternLayout.doLayout(ILoggingEvent)-----------》ch.qos.logback.core.pattern.PatternLayoutBase.writeLoopOnConverters(E)
    image.png

    如:ch.qos.logback.classic.pattern.MDCConverter
    image.png

总的来说,logback提供了相当大的自定义空间,很容易进行拓展

demo地址:https://gitee.com/eshin/logbackDemo

更多文字性描述和用法,推荐参考:

https://logback.qos.ch/manual/

https://www.cnblogs.com/lixuwu/p/5804793.html (系列)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容