目录
(一)入口:slf4j选择日志框架
(二)日志框架初始化
(1)logback的3种配置方式
a、BasicConfigurator默认配置
b、SPI方式配置的Configurator实现类
c、通过配置文件初始化
(2)xml配置文件初始化
(三)Logger的创建
(四)打印日志
本文源码基于:logback版本:1.2.11
在我们使用logback日志框架时,通常都会通过配置logback.xml定制化我们的日志需求。但你是否对loback日志如何加载配置感到好奇?如果没有logback.xml,logback的默认配置又是什么样的?配置文件中定义的appender和logger又是什么关系呢?在这一篇章我们会通过深入logback源码进行分析
(一)入口:slf4j选择日志框架
logback也是基于slf4j的一个日志框架实现。可以从maven的依赖中可以看到logback-classic依赖了slf4j-api。
所以我们使用logback日志也是使用slf4j的接口:
private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
而日志的配置加载就在首次调用LoggerFactory.getLogger时进行,具体是在LoggerFactory.getLogger-》getILoggerFactory():获取LoggerFactory时进行初始化,可以看到一个如下的performInitialization()方法。从名字可以看出这个方法就是去执行初始化的,而且使用状态位保证只初始化一次
我们接着看performInitialization方法中的bind方法:
我们知道slf4j只是定义了日志的接口,是一个日志接口协议。它将具体的日志框架实现交给各个日志框架,比如log4j2、logback等主流日志框架。这样在使用的时候,我们都是统一使用slf4j的接口,如果我们需要替换日志框架,那么只需要切换依赖,以及加上对应日志框架的配置日志就行。而之所以切换如此丝滑,就在于slf4j内部实现了日志框架实现的自动发现,即上图标红位置。
它的自动发现也很简单,只是去查找org/slf4j/impl/StaticLoggerBinder.class这个类,这个就是slf4j和具体实现框架的一个约定。如果我们想自己实现一个基于slf4j的日志框架实现,那么首先我们就得提供这么一个静态日志绑定类。
上面只是发现静态日志绑定类,如果有多个(可能同时引入了多个slf4的日志实现框架),那么会输出错误日志到控制台。并没有实际发生任何绑定动作。
实际的绑定动作是执行StaticLoggerBinder.getSingleton();
这里哪个日志框架的StaticLoggerBinder类被调用,就实际用哪个日志框架实现。
(二)日志框架初始化
上面已经讲了slf4j如何选择日志框架,最终取决于StaticLoggerBinder是哪个日志框架,这也是logback 初始化的入。接下来讲讲logback实际的初始化。
StaticLoggerBinder将绑定ILoggerFactory,使用单例模式,通过StaticLoggerBinder.getSingleton().getLoggerFactory()获取ILoggerFactory对象。它的初始化是在静态代码块中调用单例的初始化方法:SINGLETON.init();
它初始化了一个ContextInitializer,并传入StaticLoggerBinder中的默认LoggerContext,所有的初始化配置都是LoggerContext管理,实际上getLoggerFactory也是返回的此对象,所以它实际也是logger的工厂类。之后调用autoConfig,进行配置。我们重点看一下autoConfig:
(1)logback的3种配置方式
从上述代码可以看到3种配置方式的选择顺序:一个是通过获取配置文件,如果没有配置文件,那么就尝试加载SPI方式配置的Configurator实现类。如果也没有,那么会使用默认BasicConfigurator。三种配置都有两个关键步骤:
configurator.setContext(loggerContext); configurator.doConfigure(loggerContext);
首先设置日志上下文,因为所有的配置都是围绕上下文的,所以它是配置器不可或缺的。第二步就是调用doConfigure,执行上下文执行实际的配置。
下面我们从简单到复杂一一介绍:
a、BasicConfigurator默认配置
默认配置很简单:
将ConsoleAppender附加到root logger,ConsoleAppender的layout设置为TTLLLayout,它等同于%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"。所以它等同于使用如下配置文件:
<configuration>
<!-- Appenders -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Root Logger -->
<root>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
日志级别没有指定,默认是debug级别