序
本文主要研究一下TraceIdPatternLogbackLayout
TraceIdPatternLogbackLayout
org/apache/skywalking/apm/toolkit/log/logback/v1/x/TraceIdPatternLogbackLayout.class
代码语言:javascript复制public class TraceIdPatternLogbackLayout extends PatternLayout {
public TraceIdPatternLogbackLayout() {
}
static {
defaultConverterMap.put("tid", LogbackPatternConverter.class.getName());
}
}
skywalking的TraceIdPatternLogbackLayout继承了PatternLayout,其static方法往defaultConverterMap添加了tid,value为LogbackPatternConverter.class.getName()
PatternLayout
ch/qos/logback/classic/PatternLayout.java
代码语言:javascript复制public class PatternLayout extends PatternLayoutBase<ILoggingEvent> {
public static final Map<String, String> defaultConverterMap = new HashMap<String, String>();
public static final String HEADER_PREFIX = "#logback.classic pattern: ";
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());
}
public PatternLayout() {
this.postCompileProcessor = new EnsureExceptionHandling();
}
public Map<String, String> getDefaultConverterMap() {
return defaultConverterMap;
}
public String doLayout(ILoggingEvent event) {
if (!isStarted()) {
return CoreConstants.EMPTY_STRING;
}
return writeLoopOnConverters(event);
}
@Override
protected String getPresentationHeaderPrefix() {
return HEADER_PREFIX;
}
}
PatternLayout继承了PatternLayoutBase,其static方法往defaultConverterMap添加了一系列的convert
PatternLayoutBase
ch/qos/logback/core/pattern/PatternLayoutBase.java
代码语言:javascript复制abstract public class PatternLayoutBase<E> extends LayoutBase<E> {
static final int INTIAL_STRING_BUILDER_SIZE = 256;
Converter<E> head;
String pattern;
protected PostCompileProcessor<E> postCompileProcessor;
Map<String, String> instanceConverterMap = new HashMap<String, String>();
protected boolean outputPatternAsHeader = false;
//......
/**
* Concrete implementations of this class are responsible for elaborating the
* mapping between pattern words and converters.
*
* @return A map associating pattern words to the names of converter classes
*/
abstract public Map<String, String> getDefaultConverterMap();
/**
* Returns a map where the default converter map is merged with the map
* contained in the context.
*/
public Map<String, String> getEffectiveConverterMap() {
Map<String, String> effectiveMap = new HashMap<String, String>();
// add the least specific map fist
Map<String, String> defaultMap = getDefaultConverterMap();
if (defaultMap != null) {
effectiveMap.putAll(defaultMap);
}
// contextMap is more specific than the default map
Context context = getContext();
if (context != null) {
@SuppressWarnings("unchecked")
Map<String, String> contextMap = (Map<String, String>) context.getObject(CoreConstants.PATTERN_RULE_REGISTRY);
if (contextMap != null) {
effectiveMap.putAll(contextMap);
}
}
// set the most specific map last
effectiveMap.putAll(instanceConverterMap);
return effectiveMap;
}
}
PatternLayoutBase继承了LayoutBase,它定义了抽象类getDefaultConverterMap,而getEffectiveConverterMap方法返回的effectiveMap则包含了defaultConverterMap,它还包含了context中key为CoreConstants.PATTERN_RULE_REGISTRY注册的,以及本身定义的instanceConverterMap
LogbackPatternConverter
org/apache/skywalking/apm/toolkit/log/logback/v1/x/LogbackPatternConverter.class
代码语言:javascript复制public class LogbackPatternConverter extends ClassicConverter {
public LogbackPatternConverter() {
}
public String convert(ILoggingEvent iLoggingEvent) {
return "TID: N/A";
}
}
LogbackPatternConverter继承了ClassicConverter,其convert方法返回
TID: N/A
ClassicConverter
ch/qos/logback/classic/pattern/ClassicConverter.java
代码语言:javascript复制abstract public class ClassicConverter extends DynamicConverter<ILoggingEvent> {
}
ClassicConverter继承了DynamicConverter,其泛型为ILoggingEvent
DynamicConverter
ch/qos/logback/core/pattern/DynamicConverter.java
代码语言:javascript复制abstract public class DynamicConverter<E> extends FormattingConverter<E> implements LifeCycle, ContextAware {
ContextAwareBase cab = new ContextAwareBase(this);
// Contains a list of option Strings.
private List<String> optionList;
/**
* Is this component active?
*/
protected boolean started = false;
/**
* Components that depend on options passed during configuration can override
* this method in order to make appropriate use of those options. For simpler
* components, the trivial implementation found in this abstract class will be
* sufficient.
*/
public void start() {
started = true;
}
public void stop() {
started = false;
}
public boolean isStarted() {
return started;
}
public void setOptionList(List<String> optionList) {
this.optionList = optionList;
}
/**
* Return the first option passed to this component. The returned value may be
* null if there are no options.
*
* @return First option, may be null.
*/
public String getFirstOption() {
if (optionList == null || optionList.size() == 0) {
return null;
} else {
return optionList.get(0);
}
}
protected List<String> getOptionList() {
return optionList;
}
public void setContext(Context context) {
cab.setContext(context);
}
public Context getContext() {
return cab.getContext();
}
public void addStatus(Status status) {
cab.addStatus(status);
}
public void addInfo(String msg) {
cab.addInfo(msg);
}
public void addInfo(String msg, Throwable ex) {
cab.addInfo(msg, ex);
}
public void addWarn(String msg) {
cab.addWarn(msg);
}
public void addWarn(String msg, Throwable ex) {
cab.addWarn(msg, ex);
}
public void addError(String msg) {
cab.addError(msg);
}
public void addError(String msg, Throwable ex) {
cab.addError(msg, ex);
}
}
DynamicConverter继承了FormattingConverter,声明实现LifeCycle, ContextAware接口
FormattingConverter
ch/qos/logback/core/pattern/FormattingConverter.java
代码语言:javascript复制abstract public class FormattingConverter<E> extends Converter<E> {
static final int INITIAL_BUF_SIZE = 256;
static final int MAX_CAPACITY = 1024;
FormatInfo formattingInfo;
final public FormatInfo getFormattingInfo() {
return formattingInfo;
}
final public void setFormattingInfo(FormatInfo formattingInfo) {
if (this.formattingInfo != null) {
throw new IllegalStateException("FormattingInfo has been already set");
}
this.formattingInfo = formattingInfo;
}
@Override
final public void write(StringBuilder buf, E event) {
String s = convert(event);
if (formattingInfo == null) {
buf.append(s);
return;
}
int min = formattingInfo.getMin();
int max = formattingInfo.getMax();
if (s == null) {
if (0 < min)
SpacePadder.spacePad(buf, min);
return;
}
int len = s.length();
if (len > max) {
if (formattingInfo.isLeftTruncate()) {
buf.append(s.substring(len - max));
} else {
buf.append(s.substring(0, max));
}
} else if (len < min) {
if (formattingInfo.isLeftPad()) {
SpacePadder.leftPad(buf, s, min);
} else {
SpacePadder.rightPad(buf, s, min);
}
} else {
buf.append(s);
}
}
}
FormattingConverter继承了Converter,它定义了formattingInfo属性,其write方法根据formattingInfo信息进行append
示例
代码语言:javascript复制 <property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%thread] [%tid] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>${PATTERN_DEFAULT}</pattern>
</layout>
</encoder>
</appender>
这里采用了TraceIdPatternLogbackLayout,并在pattern中使用了tid
小结
skywalking的apm-toolkit-logback-1.x组件提供了TraceIdPatternLogbackLayout,可以在日志中打印tid。