初探logback日志框架
logback简介
Logback is intended as a successor to the popular log4j project. It was designed by Ceki Gülcü, log4j’s founder. It builds upon a decade of experience gained in designing industrial-strength logging systems. The resulting product, i.e. logback, is faster and has a smaller footprint than all existing logging systems, sometimes by a wide margin. Just as importantly, logback offers unique and rather useful features missing in other logging systems.
对比其他日志框架
1.logback属于slf4j阵营;log4j2属于common logging阵营。
2.Java中,logback和log4j2都是目前最流行的日志框架。
3.开发公司不同,log4j2是apache开发,而logback由qos开发。
执行流程
大体流程:创建LoggerFactory->创建Logger->过滤日志->根据日志级别输出日志->根据同异步处理日志
1.通过StaticLoggerBinder创建了一个单例的LoggerFactory,初始化时利用了双从检验锁的形式获得了一个单例的LoggerFactory。
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
2.利用获得的LoggerFactory创建了一个树状的Logger树,当然也会用缓存存一份来加快加载速度,缓存用了concurrentHashMap来保证线程安全。
// if the desired logger does not exist, them create all the loggers
// in between as well (if they don't already exist)
String childName;
while (true) {
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
// move i left of the last point
i = h + 1;
synchronized (logger) {
childLogger = logger.getChildByName(childName);
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
loggerCache.put(childName, childLogger);
incSize();
}
}
logger = childLogger;
if (h == -1) {
return childLogger;
}
可以看到用了loggerCache作为缓存,真正加载日志树的时候也用了synchronized来保证线程安全。
真正创建日志树节点的在:
Logger createChildByName(final String childName) {
int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
if (i_index != -1) {
throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
+ " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
}
if (childrenList == null) {
childrenList = new CopyOnWriteArrayList<Logger>();
}
Logger childLogger;
childLogger = new Logger(childName, this, this.loggerContext);
childrenList.add(childLogger);
childLogger.effectiveLevelInt = this.effectiveLevelInt;
return childLogger;
}
可以看到初始化了一个个的日志树节点,但是节点却用到了CopyOnWriteArrayList来保证线程安全,而且这个方法只有一个地方在调用,调用的地方用了synchronized锁,理论上在这里使用CopyOnWriteArrayList是多余的,反而会增加开销。 但是,synchronized锁的是一个日志树的节点。
在真正调用logger.info/logger.debug…时,根据配置的TurboFilterChain和effectiveLevelInt来确定是否输出日志
private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
final Throwable t) {
final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
if (decision == FilterReply.NEUTRAL