logback的TimeBasedRollingPolicy源码执行逻辑

3,308 阅读3分钟

这篇主要内容为:从入口处ch.qos.logback.core.rolling.RollingFileAppender#subAppend方法查看源码,核心内容有两点:1.ch.qos.logback.core.rolling.TriggeringPolicy#isTriggeringEvent2.ch.qos.logback.core.rolling.TimeBasedRollingPolicy#rollover

比如说,我们现在有如下的logback.xml配置。是基于时间,每小时分割并gz压缩日志文件。那么它是如何执行的呢?

1.png

如果想分析如何执行的,那么首先打开RollingFileAppender类,找到入口处,纵观此类,二百多行的代码,一目了然,找到最核心的方法,如下

2.png

可以看到,在追加文件时,会判断isTriggeringEvent,如果true,则执行rollover,否则,直接追加文件内容,subAppend内容此次不展开,重点看isTriggeringEvent和rollover的逻辑。

isTriggeringEvent

3.png

此处的timeBasedFileNamingAndTriggeringPolicy是一个接口,在TimeBasedRollingPolicy类的start方法中,会判断,如果为空,将赋值为DefaultTimeBasedFileNamingAndTriggeringPolicy

4.png

那么,好!

查看ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy#isTriggeringEvent

5.png

nextCheck

一路追代码(查看声明和引用),最终会到ch.qos.logback.core.rolling.helper.RollingCalendar#innerGetEndOfNextNthPeriod

image.png

此处逻辑为,会根据periodicityType来增加时间,那么这个值是如何赋值的呢?继续追代码,查看此方法的调用,有两个调用处,一个是我们刚点进来的位置,顺着另外一个往上追代码,会走到computePeriodicityType方法处,此方法会将计算periodicityType的值。

computePeriodicityType

这块就有意思了。为什么呢?在配置文件里,其实只设置了一个时间格式,那么这个周期类型是如何计算的呢,如果是自己实现,会怎样实现这个功能呢? 先来看看logback的实现方式。

image.png

核心逻辑为如果在xml中配置的日期格式为空,则会返回错误;不为空的时候,会按照时间单位从小到大判断(毫秒->秒->分->小时->天->星期->月),按照xml中设置的日期格式化格式,取一个当前时间,再按照当前遍历的时间单位,加1,判断两个日期是否相等,如果不相等,则返回当前遍历的时间单位。

PS:1.ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicyBase#start中会设置值,此处不展开;2.执行时,如果当前满足触发条件,会计算下次触发时间,底层逻辑也是这一套

注意

rollover不是时间驱动的,而是事件驱动,如果配置按天,不一定是0点0分会触发切分,需要产生日志才会触发是否切分的判断。总结来说,虽迟但到。 image.png

rollover

ch.qos.logback.core.rolling.RollingFileAppender#rollover

image.png

可以看到,借助ReentrantLock实现了控制线程同步逻辑,保证只有一个现成会执行rollover操作。代码很整洁,1.关流;2.rollover;3.打开新的日志文件。此处我们重点关注rollover的逻辑。ch.qos.logback.core.rolling.TimeBasedRollingPolicy#rollover

image.png

renameRawAndAsyncCompress方法最后也会调用到compressor.asyncCompress

image.png 可以看到,CompressionRunnable实现了Runnable接口,通过上下文拿到当前线程池,ScheduledExecutorService是一个可以实现重复执行或延迟任务的线程池,然后执行压缩操作。

可以自行延申:1.线程池;2.ScheduledExecutorService和timer

compress

由于在开头已经确认过背景,采用的是gz压缩,所以重点看gz压缩的逻辑。ch.qos.logback.core.rolling.helper.Compressor#gzCompress

image.png 其实核心逻辑就这么点,调用rt.jar中的GZIPOutputStream来实现压缩功能,没了。

其它

还有别的实现方案也可以使用,logback 只负责日期输出和拆分,通过linux的crontab定时执行tar或者zip命令,也可以。

参考

logback官网 - TimeBasedRollingPolicy