源码基于logback 1.1.7
本文将分析logger打印日志功能的源码,比如logger.info("hi"):
//ch.qos.logback.classic.Logger
public void info(String msg) {
filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
}
/**
* The next methods are not merged into one because of the time we gain by not
* creating a new Object[] with the params. This reduces the cost of not
* logging by about 20 nanoseconds.
*/
private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,final Throwable t) {
final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
if (decision == FilterReply.NEUTRAL) {
if (effectiveLevelInt > level.levelInt) {
return;
}
} else if (decision == FilterReply.DENY) {
return;
}
//构建loggingEvent并进行日志输出处理
buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
}
private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,final Throwable t) {
//构建loggingEvent对象,主要设置日志级别以及日志内容。
LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
le.setMarker(marker);
//执行logger下所有的appender
callAppenders(le);
}
//首先获取logger本身的appender list进行处理,处理完后判断logger的additive属性是不是true,false的立即停止,true的话
//得到他的父级logger,比如com.logback.test.LoggerTest对应的logger的父级logger是com.logback.test对应的logger。
//然后使用他的父级logger的appender list进行处理,处理完后并重复之前的逻辑,直到root或则additive为false。
public void callAppenders(ILoggingEvent event) {
int writes = 0;
for (Logger l = this; l != null; l = l.parent) {
writes += l.appendLoopOnAppenders(event);
if (!l.additive) {
break;
}
}
// No appenders in hierarchy
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
}
}
接下来分析Logger的appendLoopOnAppenders方法:
private int appendLoopOnAppenders(ILoggingEvent event) {
if (aai != null) {
return aai.appendLoopOnAppenders(event);
} else {
return 0;
}
}
//AppenderAttachableImpl
public int appendLoopOnAppenders(E e) {
int size = 0;
//appenderList是该logger的所有的appender,然后循环调用appender的doAppend方法
for (Appender<E> appender : appenderList) {
appender.doAppend(e);
size++;
}
return size;
}
下面我们用RollingFileAppender的doAppend方法来分析下:
public void doAppend(E eventObject) {
// WARNING: The guard check MUST be the first statement in the
// doAppend() method.
// prevent re-entry.
if (Boolean.TRUE.equals(guard.get())) {
return;
}
try {
guard.set(Boolean.TRUE);
if (!this.started) {
if (statusRepeatCount++ < ALLOWED_REPEATS) {
addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
}
return;
}
if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
return;
}
// ok, we now invoke derived class' implementation of append
//核心,下面分析
this.append(eventObject);
} catch (Exception e) {
if (exceptionCount++ < ALLOWED_REPEATS) {
addError("Appender [" + name + "] failed to append.", e);
}
} finally {
guard.set(Boolean.FALSE);
}
}
//OutputStreamAppender
protected void append(E eventObject) {
if (!isStarted()) {
return;
}
subAppend(eventObject);
}
//RollingFileAppender
protected void subAppend(E event) {
// The roll-over check must precede actual writing. This is the
// only correct behavior for time driven triggers.
// We need to synchronize on triggeringPolicy so that only one rollover
// occurs at a time
synchronized (triggeringPolicy) {
//判断是否触发trigger policy,比如基于时间策略来归档日志的,会判断当前时间是不是大于下次检测的时间戳,
//如果大于则会设置下次检测时间戳进行日志归档。
if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
//假如输出日志文件未info.log,这里便会关闭info.log输出流,然后对他进行归档,比如info.2017.06.08.log,
//最后重新创建info.log,打开输出流,等待后续日志写入
rollover();
}
}
//调用OutputStreamAppender的subAppend方法
super.subAppend(event);
}
//OutputStreamAppender
protected void subAppend(E event) {
if (!isStarted()) {
return;
}
try {
// this step avoids LBCLASSIC-139
if (event instanceof DeferredProcessingAware) {
((DeferredProcessingAware) event).prepareForDeferredProcessing();
}
// the synchronization prevents the OutputStream from being closed while we
// are writing. It also prevents multiple threads from entering the same
// converter. Converters assume that they are in a synchronized block.
//正如上面所说,这里加锁是为了保护当我们正在写的时候输出流被关闭,还有就是防止多个线程进入操作
lock.lock();
try {
//输出日志
writeOut(event);
} finally {
lock.unlock();
}
} catch (IOException ioe) {
// as soon as an exception occurs, move to non-started state
// and add a single ErrorStatus to the SM.
this.started = false;
addStatus(new ErrorStatus("IO failure in appender", this, ioe));
}
}
protected void writeOut(E event) throws IOException {
this.encoder.doEncode(event);
}
//LayoutWrappingEncoder
public void doEncode(E event) throws IOException {
//根据encoder partten转换msg为真正的输出内容
String txt = layout.doLayout(event);
//转化成byte然后输出到日志文件中
outputStream.write(convertToBytes(txt));
if (immediateFlush)
outputStream.flush();
}