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

63 篇文章 11 订阅

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值