logback_2-Encoder,Layout

文章目录

一 What is an encoder

Encoders就是把 LoggingEvent转化为字节数组并向 OutputStream(输出流)写出的这么个东东.

Layouts 就是能够把 LoggingEvent转换成字符串的东东.

相比较之下, Layouts既不能控制 LoggingEvent何时输出, 也不能把 LoggingEvent聚合成批(batches). 但是 Encoder既能控制 LoggingEvent输出格式,也能控制 LoggingEvent何时输出.

不过PatternLayoutEncoder才是真正有用的encoder. 它是对PatternLayout的包装.

咋说呢, encoder的抽象有点鸡肋,有啥不干脆把 layout的职责也涵盖了算了?

二 Encoder interface

Encoder有2个作用:

  • 转化LoggingEvent为字节数组
  • 将字节数组通过合适的OutputStream输出
public interface Encoder<E> extends ContextAware, LifeCycle {

   /**
   * This method is called when the owning appender starts or whenever output
   * needs to be directed to a new OutputStream, for instance as a result of a
   * rollover.
   */
  void init(OutputStream os) throws IOException;

  /**
   * 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;


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

LayoutWrappingEncoder bridges(桥接) the gap between encoders and layouts. It implements the encoder interface and wraps a layout to which it delegates the work of transforming an event into string.

(注: LayoutWrappingEncoder的出现本质上是历史设计缺陷, 其实 Layout是没有必要单独拎出来的抽象, 而是完全可以作为 Encoder的一部分)

看代码就一目了然:

public class LayoutWrappingEncoder<E> extends EncoderBase<E> {

  protected Layout<E> layout;
  private Charset charset;
 
   // encode a given event as a byte[]
   public byte[] encode(E event) {
     String txt = layout.doLayout(event);
     return convertToBytes(txt);
  }

  private byte[] convertToBytes(String s) {
    if (charset == null) {
      return s.getBytes();
    } else {
      return s.getBytes(charset);
    }
  } 
}

四 PatternLayoutEncoder

PatternLayoutEncoder是应用最为广泛 的layout,也是对 LayoutWrappingEncoder的扩展(扩展了PatternLayout职责). 从 0.9.19 版本的logback 开始, FileAppender及其子类只要配置PatternLayout就一定会使用 PatternLayoutEncoder.

五 Layouts

Layouts就是把 LoggingEvent格式化成字符串的组件(component).
我们看看接口定义:

public interface Layout<E> extends ContextAware, LifeCycle {

  String doLayout(E event);
  String getFileHeader();
  String getPresentationHeader();
  String getFileFooter();
  String getPresentationFooter();
  String getContentType();
}

在logback-classic里实际只会处理 ILoggingEvent 类型的 Event,而不会处理 AccessEvent类型的Event

六 PatternLayout

我们可以自己写一个 Layout,但坦白说, 官方给出来的 Layout已经能够满足日常需要了.往深了想, 打个日志而已, 把格式打出花来,那不也只是日志吗?

logback-classic 有一个很灵活的PatternLayout,当然它的主要职责也是拿到一个logging event,返回一个字符串.只不过这个字符串是被 PatternLayout格式化的. 格式化就是所谓的conversion pattern.

logback的 conversion pattern 和 C语言的printf 很类似.

尽管前面已经提到过, 但 FileAppender及其子类需要一个Encoder.比如常用的ConsoleAppender就使用了PatternLayoutEncoder.

我们看个栗子:

static public void main(String[] args) throws Exception {
    Logger rootLogger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    LoggerContext loggerContext = rootLogger.getLoggerContext();
    // we are not interested in auto-configuration
    loggerContext.reset();

    PatternLayoutEncoder encoder = new PatternLayoutEncoder();
    encoder.setContext(loggerContext);
    encoder.setPattern("%-5level [%thread]: %message%n");
    encoder.start();

    ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<ILoggingEvent>();
    appender.setContext(loggerContext);
    appender.setEncoder(encoder); 
    appender.start();

    rootLogger.addAppender(appender);

    rootLogger.debug("Message 1"); 
    rootLogger.warn("Message 2");
  }

这里的conversion pattern 就是 %-5level [%thread]: %message%n 这一坨.

上一篇:Transformer


下一篇:Transformer学习笔记