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

1,配置方法


    
        [%-5level] %date --%thread-- [%logger] %msg %n
    

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.
   * 

* Most subclasses of WriterAppender 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 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 lwe = new LayoutWrappingEncoder();
    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()上,然后线程爆满,内存溢出都可能会出现。

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


你可能感兴趣的:(框架,Java,Logback,console,控制台,源码)