1.设置文件写入
ch.qos.logback.core.rolling.RollingFileAppender
ch.qos.logback.core.FileAppender#start(打开日志文件openFile())
ch.qos.logback.core.OutputStreamAppender#start
ch.qos.logback.core.UnsynchronizedAppenderBase#start(设置started=true)
然后供ch.qos.logback.core.UnsynchronizedAppenderBase#doAppend写入日志数据
2. 日志写入
ch.qos.logback.classic.Logger#info(String, Object)
ch.qos.logback.classic.Logger#buildLoggingEventAndAppend
ch.qos.logback.classic.Logger#callAppenders
ch.qos.logback.classic.Logger#appendLoopOnAppenders
ch.qos.logback.core.spi.AppenderAttachableImpl#appendLoopOnAppenders
ch.qos.logback.core.AppenderBase#doAppend
ch.qos.logback.core.net.SyslogAppenderBase#append(一个实现)
ch.qos.logback.core.AsyncAppenderBase#append(使用阻塞队列实现)
ch.qos.logback.core.AsyncAppenderBase.Worker#run
ch.qos.logback.core.UnsynchronizedAppenderBase#doAppend
ch.qos.logback.core.OutputStreamAppender#append
ch.qos.logback.core.OutputStreamAppender#subAppend
数据源(具体执行的appender策略):AppenderAttachableImpl#appenderList
AppenderAttachableImpl#addAppender
AsyncAppenderBase#addAppender
AppenderRefAction#begin(在xml初始化时实现调用)
阻塞队列(生产者-消费者模型)
http://ifeve.com/java-blocking-queue/
2. 异步清除文件任务
https://www.jianshu.com/p/d9c08785430a
- TimeBasedArchiveRemover#cleanAsynchronously
- 使用ScheduledThreadPoolExecutor
- 核心方法
ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover#capTotalSize
//根据配置的MaxHistory,按照FileNamePattern遍历文件,根据规则进行删除
(1)删除次序优先最老的
(2)核心清理:ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover#cleanPeriod(按天清理)
(2.1)computeElapsedPeriodsSinceLastClean
//如果尚未执行过清理操作,则默认清理除保留天数外64天以内的日志(由INACTIVITY_TOLERANCE_IN_MILLIS决定)
//如果已经执行过清理操作,则清理从上次到当前时间的需要清理的时间周期。
(2.2)
getPeriodOffsetForDeletionTarget(根据配置的MaxHistory计算要删除的具体日期)
(2.3)getFilesInPeriod(根据FileNamePattern正则匹配获得要删除日期的日志文件名)
(3)总大小规则清理:配置totalSizeCap之后,如果总大小超限,超限之后的旧文件删除
3.logback如何解析xml文件
ch.qos.logback.classic.jmx.JMXConfigurator#reloadByFileName
ch.qos.logback.classic.jmx.JMXConfigurator#reloadByURL
ch.qos.logback.core.joran.GenericConfigurator#doConfigure(java.net.URL)
GenericConfigurator#doConfigure(InputStream, String)
* GenericConfigurator#doConfigure(InputSource)
* GenericConfigurator#doConfigure(List<SaxEvent>)
* EventPlayer#play
//不同策略的初始化
Interpreter#startElement(StartEvent)
Interpreter#startElement(String, String, String, Attributes)
Interpreter#callBeginAction
--action.begin(interpretationContext, tagName, atts);
AppenderAction#begin
AppenderRefAction#begin
//不同policy的触发
Interpreter#endElement(EndEvent)(触发不同的策略)
Interpreter#callEndAction
AppenderAction#end
((LifeCycle) appender).start();(根据不同策略的各种具体实现)
//初始化与触发的数据交互
Interpreter#actionListStack
//写入
actionListStack.add(applicableActionList);
//取出
List<Action> applicableActionList = actionListStack.peek();
List<Action> applicableActionList = (List<Action>) actionListStack.pop();
不同标签的解析和处理
- ch.qos.logback.core.joran.action.Action(logback.xml中name、class、pattern、value等标签)
AppenderAction#begin
(1)获取class标签的className
(2)反射生成对应的class,然后转化为appender
(3)获取name标签对应的appenderName,置入appender
(4)将appender放入InterpretationContext
(5)appender的使用:AppenderAction#end