Logback输出日志到控制台的配置方法和源码分析

来源:互联网 发布:淘宝客贷款哪里进 编辑:程序博客网 时间:2024/06/10 10:38

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()上,然后线程爆满,内存溢出都可能会出现。

除非必要,还是不要往控制台输出日志比较好。