2. Logback 源码分析
// log.info("user:{}", "tinyspot");
// slf4j
public void info(String format, Object arg);
// logback 实现:ch.qos.logback.classic.Logger#info
public void info(String format, Object arg) {
this.filterAndLog_1(FQCN, (Marker)null, Level.INFO, format, arg, (Throwable)null);
}
private void buildLoggingEventAndAppend(String localFQCN, Marker marker, Level level, String msg, Object[] params, Throwable t) {
LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
le.setMarker(marker);
this.callAppenders(le);
}
2.1 callAppenders(ILoggingEvent event)
- appendLoopOnAppenders()
- ch.qos.logback.core.Appender#doAppend
public void callAppenders(ILoggingEvent event) {
int writes = 0;
for (Logger l = this; l != null; l = l.parent) {
// Invoke all the appenders of this logger
writes += l.appendLoopOnAppenders(event);
if (!l.additive) {
// 如果子logger 和 父logger 都绑定了同样的 appender, 日志会重复记录;如果不想重复记录,指定additivity="false"
break;
}
}
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
}
}
public int appendLoopOnAppenders(E e) {
// ...
for (int i = 0; i < len; i++) {
appenderArray[i].doAppend(e);
size++;
}
}
ch.qos.logback.core.UnsynchronizedAppenderBase#doAppend
public void prepareForDeferredProcessing() {
// format message
this.getFormattedMessage();
this.getThreadName();
this.getMDCPropertyMap();
}
6. 动态构造 logger 对象
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
@Test
public void test() {
// LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
// StatusPrinter.print(context);
getLogger("org.demo").info("this is my custom logger");
}
public static Logger getLogger(String name) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
if (loggerContext.exists(name) == null) {
Logger logger = loggerContext.getLogger(name);
RollingFileAppender rollingFileAppender = new RollingFileAppender();
rollingFileAppender.setName(name);
rollingFileAppender.setContext(loggerContext);
TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
rollingPolicy.setFileNamePattern("/log/" + name + ".%d{yyyy-MM-dd}.log");
rollingPolicy.setParent(rollingFileAppender);
rollingPolicy.setContext(loggerContext);
rollingPolicy.start();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setCharset(StandardCharsets.UTF_8);
encoder.setPattern("%m%n");
encoder.setContext(loggerContext);
encoder.start();
rollingFileAppender.setRollingPolicy(rollingPolicy);
rollingFileAppender.setEncoder(encoder);
rollingFileAppender.start();
logger.addAppender(rollingFileAppender);
logger.setAdditive(false);
logger.setLevel(Level.INFO);
return logger;
}
return null;
}
8. Logback 的 MDC 解析
- 多线程间应用
- Mapped Diagnostic Context, 一个线程安全的存放诊断日志的容器
- 使用 MDC 之前需要在配置文件加上 %X{REQUEST}
- MDC, MDCAdapter, LogbackMDCAdapter
- 用处
- 在日志中记录用户IP, 请求URL,统计耗时等
- 在MDC中填充 REQUEST ID
追踪单个请求的执行轨迹
- 微服务场景下,使用 MDC埋点,做到链路跟踪,
多个系统日志的拼接
网友评论