1,配置方法
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<pattern>[%-5level] %date --%thread-- [%logger] %msg %n</pattern>
</encoder>
</appender>
2,源码
当调用Logger.info()方法时,会执行ConsoleAppender类的append方法。
具体调用过程可以看这里:http://blog.csdn.net/lkforce/article/details/76637071
ConsoleAppender的append方法在他的父类OutputStreamAppender中:
protected void append(E eventObject) {
if (!isStarted()) {
return;
}
subAppend(eventObject);
}
然后subAppend方法:
/**
* Actual writing occurs here.
* <p>
* Most subclasses of <code>WriterAppender</code> will need to override this
* method.
*
* @since 0.9.0
*/
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));
}
}
这里用到了一个锁:ReentrantLock,输出日志之前加锁,finally里面解锁。
writeOut方法是这样的:
protected void writeOut(E event) throws IOException {
this.encoder.doEncode(event);
}
这里的encoder使用的是LayoutWrappingEncoder,是在setLayout方法里指定的:
public void setLayout(Layout<E> layout) {
addWarn("This appender no longer admits a layout as a sub-component, set an encoder instead.");
addWarn("To ensure compatibility, wrapping your layout in LayoutWrappingEncoder.");
addWarn("See also "+CODES_URL+"#layoutInsteadOfEncoder for details");
LayoutWrappingEncoder<E> lwe = new LayoutWrappingEncoder<E>();
lwe.setLayout(layout);
lwe.setContext(context);
this.encoder = lwe;
}
LayoutWrappingEncoder的doEncode方法:
public void doEncode(E event) throws IOException {
String txt = layout.doLayout(event);
outputStream.write(convertToBytes(txt));
if (immediateFlush)
outputStream.flush();
}
用输出流把日志写到磁盘上,最后如果immediateFlush是true,则立即flush。immediateFlush可以在logback的配置文件中配置,默认是true。
这样写日志的流程就结束了。
另外,这种输出日志到控制台的方式是有可能导致线程阻塞甚至死锁的,貌似在压力比较大的情况可能会出现,跟控制台还有子线程的一些设定有关,我还没有具体研究。
log死锁还是挺严重的,所有线程都会卡在Logger.info()上,然后线程爆满,内存溢出都可能会出现。
除非必要,还是不要往控制台输出日志比较好。