类图
配置文件
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <Encoder> <pattern><pattern>|%p|%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%logger{10}:%line%n %m%n%n</pattern></pattern> <charset>utf-8</charset> </Encoder> </appender>
encoder主要负责输出格式和编码的处理
ch.qos.logback.core.OutputStreamAppender#subAppend
protected void subAppend(E event) { if (this.isStarted()) { try { if (event instanceof DeferredProcessingAware) { ((DeferredProcessingAware)event).prepareForDeferredProcessing(); } //<1>这里encode是PatternLayoutEncoder byte[] byteArray = this.encoder.encode(event); this.writeBytes(byteArray); } catch (IOException var3) { this.started = false; this.addStatus(new ErrorStatus("IO failure in appender", this, var3)); } } }
LayoutWrappingEncoder
<1>encode
ch.qos.logback.core.OutputStreamAppender#subAppend
->
ch.qos.logback.core.encoder.LayoutWrappingEncoder#encode
public byte[] encode(E event) { //<2>可以发现内部又委托给了layout 初始化处:<4> String txt = this.layout.doLayout(event); //<3>负责编码处理 return this.convertToBytes(txt); }
<3>
private byte[] convertToBytes(String s) { return this.charset == null ? s.getBytes() : s.getBytes(this.charset); }
<4>
layout在start方法初始化
public class PatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> { public PatternLayoutEncoder() { } //start也实现了LifeCycle 标签解析结束就会调用start public void start() { PatternLayout patternLayout = new PatternLayout(); patternLayout.setContext(this.context); patternLayout.setPattern(this.getPattern()); patternLayout.setOutputPatternAsHeader(this.outputPatternAsHeader); patternLayout.start(); this.layout = patternLayout; super.start(); } }
PatternLayout
类图
<2>doLayout
ch.qos.logback.core.OutputStreamAppender#subAppend
->
ch.qos.logback.core.encoder.LayoutWrappingEncoder#encode
->
ch.qos.logback.classic.PatternLayout#doLayout
public String doLayout(ILoggingEvent event) { //<5>判断是否开启 调用父类的格式化方法 return !this.isStarted() ? "" : this.writeLoopOnConverters(event); }
<5>
ch.qos.logback.core.OutputStreamAppender#subAppend
->
ch.qos.logback.core.encoder.LayoutWrappingEncoder#encode
->
ch.qos.logback.classic.PatternLayout#doLayout
->
ch.qos.logback.core.pattern.PatternLayoutBase#writeLoopOnConverters
protected String writeLoopOnConverters(E event) { StringBuilder strBuilder = new StringBuilder(256); /** * 将我们配置的输出格式表达式 进行转换处理 * <pattern><pattern>|%p|%d{yyyy-MM-dd HH:mm:ss.SSS}|%t|%logger{10}:%line%n %m%n%n</pattern></pattern> */ for(Converter c = this.head; c != null; c = c.getNext()) { c.write(strBuilder, event); } //返回最终输出的数据 return strBuilder.toString(); }
Converter
public abstract class Converter<E> { Converter<E> next; public Converter() { } public abstract String convert(E var1); public void write(StringBuilder buf, E event) { buf.append(this.convert(event)); } public final void setNext(Converter<E> next) { if (this.next != null) { throw new IllegalStateException("Next converter has been already set"); } else { this.next = next; } } public final Converter<E> getNext() { return this.next; } }
映射关系在PatternLayout 的static方法
static { defaultConverterMap.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP); defaultConverterMap.put("d", DateConverter.class.getName()); defaultConverterMap.put("date", DateConverter.class.getName()); defaultConverterMap.put("r", RelativeTimeConverter.class.getName()); defaultConverterMap.put("relative", RelativeTimeConverter.class.getName()); defaultConverterMap.put("level", LevelConverter.class.getName()); defaultConverterMap.put("le", LevelConverter.class.getName()); defaultConverterMap.put("p", LevelConverter.class.getName()); defaultConverterMap.put("t", ThreadConverter.class.getName()); defaultConverterMap.put("thread", ThreadConverter.class.getName()); defaultConverterMap.put("lo", LoggerConverter.class.getName()); defaultConverterMap.put("logger", LoggerConverter.class.getName()); defaultConverterMap.put("c", LoggerConverter.class.getName()); defaultConverterMap.put("m", MessageConverter.class.getName()); defaultConverterMap.put("msg", MessageConverter.class.getName()); defaultConverterMap.put("message", MessageConverter.class.getName()); defaultConverterMap.put("C", ClassOfCallerConverter.class.getName()); defaultConverterMap.put("class", ClassOfCallerConverter.class.getName()); defaultConverterMap.put("M", MethodOfCallerConverter.class.getName()); defaultConverterMap.put("method", MethodOfCallerConverter.class.getName()); defaultConverterMap.put("L", LineOfCallerConverter.class.getName()); defaultConverterMap.put("line", LineOfCallerConverter.class.getName()); defaultConverterMap.put("F", FileOfCallerConverter.class.getName()); defaultConverterMap.put("file", FileOfCallerConverter.class.getName()); defaultConverterMap.put("X", MDCConverter.class.getName()); defaultConverterMap.put("mdc", MDCConverter.class.getName()); defaultConverterMap.put("ex", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("exception", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("rEx", RootCauseFirstThrowableProxyConverter.class.getName()); defaultConverterMap.put("rootException", RootCauseFirstThrowableProxyConverter.class.getName()); defaultConverterMap.put("throwable", ThrowableProxyConverter.class.getName()); defaultConverterMap.put("xEx", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("xException", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("xThrowable", ExtendedThrowableProxyConverter.class.getName()); defaultConverterMap.put("nopex", NopThrowableInformationConverter.class.getName()); defaultConverterMap.put("nopexception", NopThrowableInformationConverter.class.getName()); defaultConverterMap.put("cn", ContextNameConverter.class.getName()); defaultConverterMap.put("contextName", ContextNameConverter.class.getName()); defaultConverterMap.put("caller", CallerDataConverter.class.getName()); defaultConverterMap.put("marker", MarkerConverter.class.getName()); defaultConverterMap.put("property", PropertyConverter.class.getName()); defaultConverterMap.put("n", LineSeparatorConverter.class.getName()); defaultConverterMap.put("black", BlackCompositeConverter.class.getName()); defaultConverterMap.put("red", RedCompositeConverter.class.getName()); defaultConverterMap.put("green", GreenCompositeConverter.class.getName()); defaultConverterMap.put("yellow", YellowCompositeConverter.class.getName()); defaultConverterMap.put("blue", BlueCompositeConverter.class.getName()); defaultConverterMap.put("magenta", MagentaCompositeConverter.class.getName()); defaultConverterMap.put("cyan", CyanCompositeConverter.class.getName()); defaultConverterMap.put("white", WhiteCompositeConverter.class.getName()); defaultConverterMap.put("gray", GrayCompositeConverter.class.getName()); defaultConverterMap.put("boldRed", BoldRedCompositeConverter.class.getName()); defaultConverterMap.put("boldGreen", BoldGreenCompositeConverter.class.getName()); defaultConverterMap.put("boldYellow", BoldYellowCompositeConverter.class.getName()); defaultConverterMap.put("boldBlue", BoldBlueCompositeConverter.class.getName()); defaultConverterMap.put("boldMagenta", BoldMagentaCompositeConverter.class.getName()); defaultConverterMap.put("boldCyan", BoldCyanCompositeConverter.class.getName()); defaultConverterMap.put("boldWhite", BoldWhiteCompositeConverter.class.getName()); defaultConverterMap.put("highlight", HighlightingCompositeConverter.class.getName()); defaultConverterMap.put("lsn", LocalSequenceNumberConverter.class.getName()); }
我们可以进行扩展自己的convert 如参考LevelConverter
public class LevelConverter extends ClassicConverter { public LevelConverter() { } public String convert(ILoggingEvent le) { return le.getLevel().toString(); } }
总结
1.appender输出文件是给encoder
2.encoder再委托给layout
3.如果是PatternLayout patternLayout支持输出格式定义 输出格式定义是根据Converter来的 我们可以自定义convert 比如TraceIdConvert