本文分析源码,Logback版本为1.2.3,SLF4J的版本为1.7.25
使用SLF4J作为Log Facade,使用Logback作为具体Log Implementation,配置好logback.xml之后,执行以下代码,就可以使用Logback打印日志。
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MainTest01 {
@Test
public void test01() {
Logger logger = LoggerFactory.getLogger(MainTest01.class);
logger.error("i am in logback...");
}
}
Logback是如何与SLF4J关联起来的呢,通过SLF4J与Logback、Log4j1、Log4j2、JCL、J.U.L是如何关联使用的,可以简单的知道,
本文简单分析以下org.slf4j.impl.StaticLoggerBinder的实现方式,首先在SLF4J源码当中存在未完整实现org.slf4j.impl.StaticLoggerBinder的类(主要是为了开发使用),而在打包的时候,并没有将org.slf4j.impl.StaticLoggerBinder打入Jar包当中,这里主要通过resources/META-INF/MANIFEST.MF
的配置实现,其中有如下:
Export-Package: org.slf4j;version=${parsedVersion.osgiVersion},
org.slf4j.spi;version=${parsedVersion.osgiVersion},
org.slf4j.helpers;version=${parsedVersion.osgiVersion},
org.slf4j.event;version=${parsedVersion.osgiVersion}
Import-Package: org.slf4j.impl;version=${slf4j.api.minimum.compatible.version}
其中Import-Package这是一个表示要引入的配置,Export-Package表示要打包输出的配置。这样,SLF4J的api包就没有包含org.slf4j.impl.StaticLoggerBinder,而主使用了具体实现Log的org.slf4j.impl.StaticLoggerBinder。
点击进入 LoggerFactory.getLogger的实现,我们会看到,org.slf4j.LoggerFactory#getILoggerFactory获取日志工厂的实现,其中有performInitialization()调用的 org.slf4j.LoggerFactory#bind方法,在bind方法当中有
// the next line does the binding
StaticLoggerBinder.getSingleton();
的一行代码,上面分析,StaticLoggerBinder是日志实现的StaticLoggerBinder而非SLF4J的StaticLoggerBinder,也就是说这里的StaticLoggerBinder是在Logback中实现的StaticLoggerBinder。点击进入StaticLoggerBinder可以看到StaticLoggerBinder的初始化等代码。
org.slf4j.LoggerFactory#getILoggerFactory 代码当中包含
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
这样,我们调用SLF4J的LoggerFactory.getLogger方法,就返回了Logback的LoggerFactory返回的Logger。
同时需要注意一点,StaticLoggerBinder在这里使用了单例的形式,
logback使用配置详解
Logback的初始化工作由org.slf4j.impl.StaticLoggerBinder#init完成,主要初始化代码如下
try {
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.report("Failed to auto configure default logger context", je);
}
loggerCache以ch.qos.logback.classic.MainTest01当中每一级作为key存放对应的logger,上面的路径会产生,五个Key对应的Logger,LoggerAction处理的时候会把对应的loger放到LoggerContext当中的loggerCache当中。
ch
ch.qos
ch.qos.logback
ch.qos.logback.classic
ch.qos.logback.classic.MainTest01
如果调用了logger.error(“asdf”);方法,关键路径如下:
ch.qos.logback.core.AsyncAppenderBase当中维护了一个blockingQueue,用于存放要打印的LoggingEvent日志。
blockingQueue = new ArrayBlockingQueue(queueSize);
.....
class Worker extends Thread {
public void run() {
AsyncAppenderBase parent = AsyncAppenderBase.this;
AppenderAttachableImpl aai = parent.aai;
// loop while the parent is started
while (parent.isStarted()) {
try {
E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);
} catch (InterruptedException ie) {
break;
}
}
addInfo("Worker thread will flush remaining events before exiting. ");
for (E e : parent.blockingQueue) {
aai.appendLoopOnAppenders(e);
parent.blockingQueue.remove(e);
}
aai.detachAndStopAllAppenders();
}
}
logback logback.xml常用配置详解(二)
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件,实际做日志打印的还是落到了RollingFileAppender这里。RollingFileAppender当中包含一下属性
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="/Users/zeyu/logs"/>
<property name="appName" value="MyTestProject">property>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFOlevel>
filter>
<Encoding>UTF-8Encoding>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
pattern>
layout>
appender>
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8Encoding>
<file>${LOG_HOME}/${appName}.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.logfileNamePattern>
<MaxHistory>365MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ]
- %msg%n
pattern>
layout>
appender>
<appender name="appLogAppenderAsync" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0discardingThreshold>
<queueSize>2048queueSize>
<appender-ref ref="appLogAppender"/>
appender>
<logger name="org.hibernate" level="error"/>
<logger name="org.springframework" level="error" additivity="false">logger>
<logger name="com.creditease" level="info" additivity="true">
<appender-ref ref="appLogAppenderAsync"/>
logger>
<root level="info">
<appender-ref ref="stdout"/>
<appender-ref ref="appLogAppenderAsync"/>
root>
configuration>