What is an encoder
编码器负责将事件转化为字节数组,并将字节数组转换成一个OutputStream 。
Encoder ---> Byte[] ---> OutputStream
在0.9.19版本之前,大多数的appender都依赖layout布局组件将事件转换为字符串String
在使用java.io.Writer将其写入到文件
在0.9.19版本之前,对FileAppender将在内部嵌套PatternLayout进行样式设置
从0.9.19版本开始,FileAppender将通过Encoder设置样式,不再设置layout属性了
This appender no longer admits a layout as a sub-component, set an encoder instead.
to (GOOD)
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>testFile.log</file> ... <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%msg%n</pattern> </encoder> </appender>
or the shorter equivalent (GOOD)
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>testFile.log</file> ... <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
For layout type other than PatternLayout, for example HTMLLayout, your configuration files need to be changed
to (GOOD)
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>testFile.log</file> ... <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="ch.qos.logback.classic.html.HTMLLayout"> <pattern>%msg%n</pattern> </layout> </encoder> </appender>
Layouts仅仅能够将event转换为某种样式的字符串String
此外,鉴于Layout无法控制何时对event进行写出,也没有批处理能力
Encoder不仅提供了写出字节数组的格式,还可以控制何时进行写出操作
Encoder兼备Layout样式和决定日志写出时机的功能
到目前为止,PatternLayoutEncoder是唯一真正使用的Encoder
PatternLayoutEncoder包装了一个LayoutPattern,从而提供了设置样式的功能
Encoder负责将event转换为Byte[],并将结果写到合适的OutputStream流中
这样,appender就可以通过Encoder完全控制何时将什么bytes进行写出操作
LayoutWrappingEncoder
直到logback版本0.9.19 ,许多appender都依赖于布局实例来控制日志输出格式
由于Layout 的接口已经提供了大量的样式设置功能,我们只需要将Encoder与Layout结合在一起即可
LayoutWrappingEncoder作为一个桥梁,有效的将Encoder与Layout两者结合在一起
LayoutWrappingEncoder实现了Encoder接口,并对Layout进行了包装(Layout将event转换为字符串)
由此,得到:
Event ---> Layout ---> Formated String ---> Encoder ---> Byte[] ---> OutputStream
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); } } }
PatternLayoutEncoder
鉴于PatternLayout是最常用的布局, logback这种常见的用例满足与PatternLayoutEncoder
immediateFlush property
true: 保证日志及时输出到文件,会影响系统处理日志的吞吐量;
false:可以大大提高日志处理的throughout,大概5倍,但有可能造成日志丢失(appender没有正确关闭);
<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
在输入日志的上方,输出日志的Pattern
默认为false,不在头部输出样式
<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>
This will result output akin to the following in the log file:
#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
%d 日期:2012-04-26 14:54:38,461
[%thread] 线程:[mian]
%-5level 级别:DEBUG
%logger{36} 类路径:com.foo.App
%msg 消息:Hello world
%n 换行