源码基于logback 1.1.7
logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://www.padual.com/java/logback.xsd">
<appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/Users/apple/Documents/UNKONESERVER/warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>/Users/apple/Documents/UNKONESERVER/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的保存天数 -->
<maxHistory>2</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="com.logback.test" level="debug"
additivity="false">
<appender-ref ref="WARN" />
</logger>
<root level="debug">
</root>
</configuration>
下面分析loaback是如何解析logger元素的:
1.当解析到[configuration][logger]的时候会触发[configuration][logger]的startEvent方法,最终调用LoggerAction的begin方法:
public void begin(InterpretationContext ec, String name, Attributes attributes) {
// Let us forget about previous errors (in this object)
inError = false;
logger = null;
LoggerContext loggerContext = (LoggerContext) this.context;
//获取logger name,这里是com.logback.test
String loggerName = ec.subst(attributes.getValue(NAME_ATTRIBUTE));
if (OptionHelper.isEmpty(loggerName)) {
inError = true;
String aroundLine = getLineColStr(ec);
String errorMsg = "No 'name' attribute in element " + name + ", around " + aroundLine;
addError(errorMsg);
return;
}
//根据loggerName获取logger,下面会详细分析
logger = loggerContext.getLogger(loggerName);
String levelStr = ec.subst(attributes.getValue(LEVEL_ATTRIBUTE));
if (!OptionHelper.isEmpty(levelStr)) {
if (ActionConst.INHERITED.equalsIgnoreCase(levelStr) || ActionConst.NULL.equalsIgnoreCase(levelStr)) {
addInfo("Setting level of logger [" + loggerName + "] to null, i.e. INHERITED");
logger.setLevel(null);
} else {
Level level = Level.toLevel(levelStr);
addInfo("Setting level of logger [" + loggerName + "] to " + level);
//设置logger级别,没有设置的话默认用debug
logger.setLevel(level);
}
}
String additivityStr = ec.subst(attributes.getValue(ActionConst.ADDITIVITY_ATTRIBUTE));
if (!OptionHelper.isEmpty(additivityStr)) {
boolean additive = OptionHelper.toBoolean(additivityStr, true);
addInfo("Setting additivity of logger [" + loggerName + "] to " + additive);
//在本文中例子中,如果是false,那只输出com.logback.test对应logger的日志
//如果是true,不仅会输出com.logback.test对应logger的日志,还是输出com.logback对应logger的日志
//如果com.logback对应的logger的additive也是true,那也会输出上级logger日志
logger.setAdditive(additive);
}
ec.pushObject(logger);
}
loggerContext.getLogger(loggerName):
public final Logger getLogger(final String name) {
if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}
// if we are asking for the root logger, then let us return it without
// wasting time
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}
int i = 0;
Logger logger = root;
// check if the desired logger exists, if it does, return it
// without further ado.
//从缓存中根据name获取logger对象,首次是没有值的
Logger childLogger = (Logger) loggerCache.get(name);
// if we have the child, then let us return it without wasting time
if (childLogger != null) {
return childLogger;
}
// if the desired logger does not exist, them create all the loggers
// in between as well (if they don't already exist)
//将loggerName按照.进行层级拆分,比如com.logback.test,会被查分成com, com.logback ,com.logback.test三个childName。
//然后根据这个三个childName去缓存中获取对应的logger,没有就创建,然后保存到缓存中。
//该方法最后返回childName为com.logback.test的logger。
//每个logger会保存它的父级logger。
//每个logger又会保存它的child logger,比如com对应的logger会保存com.logback对应的logger。
//ROOT logger是最顶级logger,保存所有一级logger,比如com对应的logger,也是所有一级logger的父级logger。
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;
}
}
}
2.当[configuration][logger]的startEvent结束后,会触发[configuration][logger][appender-ref]的startEvent,最终会调用AppenderRefAction的begin方法:
public void begin(InterpretationContext ec, String tagName, Attributes attributes) {
// Let us forget about previous errors (in this object)
inError = false;
// logger.debug("begin called");
//获取[configuraion][logger]对应的logger实例
Object o = ec.peekObject();
if (!(o instanceof AppenderAttachable)) {
String errMsg = "Could not find an AppenderAttachable at the top of execution stack. Near [" + tagName + "] line " + getLineNumber(ec);
inError = true;
addError(errMsg);
return;
}
AppenderAttachable<E> appenderAttachable = (AppenderAttachable<E>) o;
//获取appender name,本文例子的appender name为WARN
String appenderName = ec.subst(attributes.getValue(ActionConst.REF_ATTRIBUTE));
if (OptionHelper.isEmpty(appenderName)) {
// print a meaningful error message and return
String errMsg = "Missing appender ref attribute in <appender-ref> tag.";
inError = true;
addError(errMsg);
return;
}
//根据appender name获取对应的appender实例
HashMap<String, Appender<E>> appenderBag = (HashMap<String, Appender<E>>) ec.getObjectMap().get(ActionConst.APPENDER_BAG);
Appender<E> appender = (Appender<E>) appenderBag.get(appenderName);
if (appender == null) {
String msg = "Could not find an appender named [" + appenderName + "]. Did you define it below instead of above in the configuration file?";
inError = true;
addError(msg);
addError("See " + CoreConstants.CODES_URL + "#appender_order for more details.");
return;
}
addInfo("Attaching appender named [" + appenderName + "] to " + appenderAttachable);
//将appender实例存入logger中
appenderAttachable.addAppender(appender);
}
3.[configuration][logger][appender-ref]的startEvent结束后,触发[configuration][logger][appender-ref]的endEvent,没做任何事情。 4.接下来就是[configuration][logger]的endEvent了,但LoggerAction的end方法也没做什么事情。

被折叠的 条评论
为什么被折叠?



