encoder的作用:
Encoders 负责将日志事件转换为二进制流并且将二进制流转换为输出流。encoder是从logback的0.9.19版本引入的。在之前的版本中,appender依赖layout将日志事件转化为string。在之前的版本中需要在fileappender中嵌套一个patternlayout。在0.9.19版本后,fileappender及其子类将采用encoder而不采用layout了。
为什么做这个改变:
即将在下一章讨论的Layout组件只是负责将事件转换为String。而不对事件输出的时间以及是否采用批量方式输出进行控制。相对而言,encoder不仅能够控制输出格式还能控制输出的时机。
在现阶段,patternlayoutencoder是唯一实际有用的encoder。它仅仅是对patternlayout做了封装,因此,看起来encoder并没有带来实际的作用,但是我们希望伴随着新的encoder的出现,这种情况会有改变。
encoder interface
encoder负责将事件输出到字节流中并将生成的字节流输出到合适的输出流中。因此,encoder需要根据他的appender整体上控制字节流输向输出流的内容和时机。下面是接口的代码:
ackage ch.qos.logback.core.encoder; 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.当appender启动或者需要指向一个新的输出流时(如:滚动发生时)调用。
*/ 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; }encoder接口只有几个方法,但是却能够完成很多功能。
LayoutWrappingEncoder
指导logback的0.9.19版本,很多的appender还是依赖layout实例来控制日志的输出。这样会使layout的实现类中充斥大量的代码,因此我们需要一种方法来让encoder在layout的内部被调用执行。LayoutWrappingEncoder将encoder和layout两者关联起来了。它实现了encoder接口,并且封装了一个layout实现将日志事件转换为string。
下面是layoutwrappingencoder的一些源码:
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); } } }
doEncode方法通过封装的layout将日志事件转换为String。所得到的的String通过用户设置的字符集格式转变为字节流。然后这些字节流输出到appender设定的输出流中。默认情况下,输出流将会立即输出,除非将immediateFlush属性设置为false,将这个属性设置为false可以大大提升日志的输出效率。可以通过后面patternlayoutencoder使用的例子来学习这个属性的设置。
PatternLayoutEncoder
patternlayout是最普遍应用的layout,logback为这个建立了patternlayoutencoder,这个类继承自layoutwrappingencoder(对patternlayout的一直封装)。在logback0.9.19版本后,fileappender或者他的子类必须在其中配置一个patternlayout,一个patternlayoutencoder。
immediateFlush property
作为layoutwrappingencoder的子类,patternlayoutencoder也可以配置immediateFlush属性。这个属性的默认值是true。这个默认值会让将输出流进行输出,以便日志事件能够在第一时间输出到磁盘上,以免应用退出时没有真确的管理appender造成日志的泄漏。在另外一方面,将这个属性设置为false会将日志的输出能力提升五倍左右。需要注意的是,当这个属性设置为false时,当应用关闭时没有对appender做适当的处理,日志事件就可能会遗漏。下面的例子就是将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>
Output pattern string as header
为了便于解析日志文件,logback可以将日志的输出格式输出到日志文件的顶端。默认情况下这个属性设置为disabled。可以通过将patterlayoutencoder的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 ...
"#logback.classic pattern" 的字符输出时最近才开始加入模式行中的。
encoder学习结束!