阅读Logback文档笔记--Logback的Encoder配置

来源:互联网 发布:linux私房菜 第四版 编辑:程序博客网 时间:2024/05/18 02:05
Encoder负责将logging event转换成byte array并将字节数组写入到一个OutputStream。在0.9.19版本之前,大多数appender依赖layout来将Logging event转回成字符串string ,然后用java.io.Writer写出。在之前的版本中,用户会在FileAppender中内建PatternLayout,但从0.9.19之后,FileAppender及其子类不在使用layout而采用encoder。

为什么要做成这样的改变呢?
Layout只能将event转换成string。此外,考虑到layout没有控制events写出的过程,所以Layout无法对events进行批处理操作。与之相比,encoder不仅能控制event转换成字节数组,还能控制字节数组写出到输出流的过程。
目前来说,PatternLayoutEncoder是唯一一个有用的encoder。它仅仅是简单包装了PatternLayout,主要的工作其实都是由内部的PatternLayout完成的。

下面我们看下Encoder interface

package ch.qos.logback.core.encoder;

public interface Encoder<E extends ContextAware, LifeCycle {

  /**
  * 该方法在appender初始化或者在输出流发生重定向的时候回调用,例如滚动日志发生的时候,      
  * RollingFileAppender
  */
  void init(OutputStream os) throws IOException;

  /**
  * 将event编码以及写入到合适的输出流中。
  * 实现可以自由地推迟将被编码event写出到输出流中的时间,而不是写在一个批处理当中。
  * Encode and write an event to the appropriate {@link OutputStream}.
  * Implementations are free to defer writing out of the encoded event and
  * instead write in batches.
  */
  void doEncode(E event) throws IOException;

  /**
  * 该方法在关闭下属OutputStream前调用。它的实现必须不能主动关闭下属的OutputStream
  * This method is called prior to the closing of the underling
  * {@link OutputStream}. Implementations MUST not close the underlying
  * {@link OutputStream} which is the responsibility of the owning appender.
  */
  void close() throws IOException;
}


LayoutWrappingEncoder
在0.9.19之前,很多appenders依赖Layout格式化日志输出。因此就存在大象基于layout接口的代码,所以我们需要一种方法来兼容这些基于layout的代码。LayoutWrappingEncoder就在encoders和layout质检搭了一座桥。它既实现了encoder interface,又包装了Layout。
下面我们看看它的实现

package ch.qos.logback.core.encoder;

public class LayoutWrappingEncoder<E extends EncoderBase<E {

  protected Layout<E layout;
  private Charset charset;
  private boolean immediateFlush = true;

  public void doEncode(E event) throws IOException {
    String txt = layout.doLayout(event);
    outputStream.write(convertToBytes(txt));
    if (immediateFlush)
      outputStream.flush();
  }

  private byte[] convertToBytes(String s) {
    if (charset == null) {
      return s.getBytes();
    } else {
      return s.getBytes(charset);
    }
  }
}
整体很简单,先通过layout将event转换成string,然后转换成字节数组再通过与appender绑定的输出流输出字节数组。可以看到immediateFlush变量决定是否立刻刷新输出流缓冲区。默认为true。如果设置成false,可以显著提高日志的吞吐量。

下面看一个PatternLayoutEncoder的简单配置
考虑到PatternLayout是目前被广泛使用的layout,logbook为了迎合这种常见的使用情况,退出继承自LayoutWrappingEncoder,并且包装了PatternLayout实例的PatternLayoutEncoder。

在0.9.19版本中,FileAppender及其子类如果需要配置PatternLayout,就必须使用PatternLayoutEncoder来代替,否则会报错。更多配置错误可以查看 relevant entry in the logback error codes.

将immediateFlush设置成false,可以通过缓存日志,再一次输出的方式,提供日志吞吐量
<appender name="FILE" class="ch.qos.logback.core.FileAppender"
  <file>foo.log</file>
  <encoder>
    <pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern>
    <!-- this quadruples logging throughput -->
    <immediateFlush>false</immediateFlush>
  </encoder>
</appender>


如果将outputPatternAsHeader设置成true,则日志输出类似如下
<appender name="FILE" class="ch.qos.logback.core.FileAppender"
  <file>foo.log</file>
  <encoder>
    <pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern>
    <outputPatternAsHeader>true</outputPatternAsHeader>
  </encoder>
</appender>

结果
#logback.classic pattern: %d [%thread] %-5level %logger{36} - %msg%n
2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hello world
2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hi again 
0 0