源碼基於logback 1.1.7java
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元素的:app
1.當解析到[configuration][logger]的時候會觸發[configuration][logger]的startEvent方法,最終調用LoggerAction的begin方法:this
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):debug
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方法也沒作什麼事情。code