慢慢來比較快队萤,虛心學技術
前言:Jakarta Commons-logging(JCL)是apache最早提供的日志的門面接口匿醒。它將一些具體的日志組件抽象為接口介评,實現(xiàn)日志操作的解耦和可插拔,讓眾多的日志工具有一個共同的操作方式
一、common-logging簡單使用示例
①引入common-logging的jar包窜骄,最新jar包從官方網(wǎng)站http://commons.apache.org/proper/commons-logging/download_logging.cgi進行下載,下載后將jar包放到lib中引入項目即可摆屯。
如果是maven項目在pom文件中添加依賴如下:
<!--引入common-logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
②創(chuàng)建common-logging.properties文件,將其放在classpath下邻遏,如果是maven項目則將其放在src/main/resource目錄下,配置內(nèi)容如下
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
③在項目程序中使用logger開發(fā)
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonsTest {
//獲取logger
private final static Log logger = LogFactory.getLog(CommonsTest.class);
public static void main(String[] args) {
//使用logger輸出日志
logger.trace("TRACE...");
logger.debug("DEBUG ...");
logger.info("INFO ...");
logger.error("ERROR ...");
logger.warn("WARN...");
}
}
運行輸出結(jié)果:
[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...
如上實現(xiàn)第一個簡單的common-logging程序虐骑,引發(fā)以下幾個問題
問題一:common-logging.properties屬性文件中的org.apache.commons.logging.Log和它的值代表了什么准验?
問題二:為什么明明代碼中寫了logger.trace和logger.debug,卻沒有輸出廷没?
問題三:LogFactory的實現(xiàn)原理是什么糊饱?
帶著問題去思考學習,效率總是最高的
二颠黎、問題探索
1.org.apache.commons.logging.Log
JCL有兩個基本的抽象類: Log( 基本記錄器 ) 和 LogFactory( 負責創(chuàng)建 Log 實例 )另锋,其中滞项,Log有多個默認實現(xiàn)類,分別是:
-org.apache.commons.logging.impl.Jdk14Logger 使用JUL砰蠢。
-org.apache.commons.logging.impl.Log4JLogger 使用Log4J蓖扑。
-org.apache.commons.logging.impl.LogKitLogger 使用 avalon-Logkit唉铜。
-org.apache.commons.logging.impl.SimpleLog common-logging自帶日志實現(xiàn)類台舱。它實現(xiàn)了Log接口,把日志消息都輸出到系統(tǒng)錯誤流System.err 中潭流。
-org.apache.commons.logging.impl.NoOpLog common-logging自帶日志實現(xiàn)類竞惋。它實現(xiàn)了Log接口。 其輸出日志的方法中不進行任何操作灰嫉。
在common-logging.properties中配置的org.apache.commons.logging.Log參數(shù)指定了common-logging將使用哪種日志實現(xiàn)拆宛,這也是前言所說的,通過配置實現(xiàn)日志組件的可插拔和解耦讼撒,極大增加了靈活性
2.common-logging日志級別
common-logging日志級別從高到低如下:
1)fatal 非常嚴重的錯誤浑厚,導致系統(tǒng)中止。期望這類信息能立即顯示在狀態(tài)控制臺上根盒。
2)error 其它運行期錯誤或不是預期的條件钳幅。期望這類信息能立即顯示在狀態(tài)控制臺上。
3)warn 使用了不贊成使用的API炎滞、非常拙劣使用API, '幾乎就是'錯誤, 其它運行時不合需要和不合預期的狀態(tài)但還沒必要稱為 "錯誤"敢艰。期望這類信息能立即顯示在狀態(tài)控制臺上。
4)info 運行時產(chǎn)生的有意義的事件册赛。期望這類信息能立即顯示在狀態(tài)控制臺上钠导。
5)debug 系統(tǒng)流程中的細節(jié)信息。期望這類信息僅被寫入log文件中森瘪。
6)trace 更加細節(jié)的信息牡属。期望這類信息僅被寫入log文件中。
apache建議使用4級扼睬,即 ERROR逮栅、WARN、INFO痰驱、DEBUG
而當我們在common-logging.properties配置使用的是SimpleLog日志實現(xiàn)证芭,該日志實現(xiàn)默認日志級別是info,所以才會出現(xiàn)簡單實例中的輸出結(jié)果担映,如何更改SimpleLog的日志級別废士?
創(chuàng)建simplelog.properties配置文件,放到classpath下蝇完,如果是maven則放到src/main/resource目錄下,配置內(nèi)容參考:
org.apache.commons.logging.simplelog.defaultlog=TRACE
配置后結(jié)果輸出如下(bingo):
[TRACE] CommonsTest - TRACE...
[DEBUG] CommonsTest - DEBUG ...
[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...
3.LogFactory實現(xiàn)原理
LogFactory作為log的工廠存在官硝,使用動態(tài)查找機制進行l(wèi)og實例的獲取矗蕊,具體執(zhí)行步驟如下:
①首先在classpath下尋找commons-logging.properties文件。如果找到氢架,則使用其中定義的Log實現(xiàn)類傻咖;如果找不到,則在查找是否已定義系統(tǒng)環(huán)境變量org.apache.commons.logging.Log岖研,找到則使用其定義的Log實現(xiàn)類卿操;
②查看classpath中是否有Log4j的包,如果發(fā)現(xiàn)孙援,則自動使用Log4j作為日志實現(xiàn)類害淤;
③使用JDK自身的日志實現(xiàn)類(JDK1.4以后才有日志實現(xiàn)類);
④使用commons-logging自己提供的一個簡單的日志實現(xiàn)類SimpleLog拓售;
上述步驟當LogFactory成功找到一個日志實現(xiàn)之后就會停止
實際上窥摄,看源碼發(fā)現(xiàn),LogFactory的核心步驟在于discoverLogImplementation方法础淤,源碼分析如下:
if (isDiagnosticsEnabled()) {
this.logDiagnostic("Discovering a Log implementation...");
}
this.initConfiguration();
Log result = null;
//從common-logging.properties文件中提取org.apache.commons.logging.Log這個變量的value
String specifiedLogClassName = this.findUserSpecifiedLogClassName();
//配置文件中存在該變量則實例化
if (specifiedLogClassName != null) {
if (isDiagnosticsEnabled()) {
this.logDiagnostic("Attempting to load user-specified log class '" + specifiedLogClassName + "'...");
}
//核驗相應日志對象是否存在
result = this.createLogFromClass(specifiedLogClassName, logCategory, true);
//如果日志對象不存在崭放,則報錯
if (result == null) {
StringBuffer messageBuffer = new StringBuffer("User-specified log class '");
messageBuffer.append(specifiedLogClassName);
messageBuffer.append("' cannot be found or is not useable.");
this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Log4JLogger");
this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk14Logger");
this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.Jdk13LumberjackLogger");
this.informUponSimilarName(messageBuffer, specifiedLogClassName, "org.apache.commons.logging.impl.SimpleLog");
throw new LogConfigurationException(messageBuffer.toString());
} else {
return result;
}
} else {
//當日志文件中不存在該變量時,按照機制遍歷classesToDiscover字符串數(shù)組
if (isDiagnosticsEnabled()) {
this.logDiagnostic("No user-specified Log implementation; performing discovery using the standard supported logging implementations...");
}
//遍歷classesToDiscover字符串數(shù)組獲取日志實例(動態(tài)查找機制)
for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
}
//到最后仍舊找不到匹配的日志實例鸽凶,則拋錯
if (result == null) {
throw new LogConfigurationException("No suitable Log implementation");
} else {
return result;
}
}
三币砂、進階,common-logging+log4j應用
log4j功能強大吱瘩,為了解耦和減少依賴道伟,大部分的項目都會使用common-logging+log4j的組合進行開發(fā),使用起來也是十分的簡單:
①引入log4j的jar包使碾,最新jar包從官方網(wǎng)站http://logging.apache.org/log4j/1.2/download.html進行下載蜜徽,下載后將jar包放到lib中引入項目即可。
如果是maven項目在pom文件中添加依賴如下:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
②在common-logging.properties文件,將log指向log4j
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
③創(chuàng)建log4j.properties文件票摇,并將文件放在classpath下拘鞋,如果是maven則放在source/main/resource目錄下,簡單配置如下:
#配置rootLogger
log4j.rootLogger=all,appender1
#配置第一個appender
log4j.appender.appender1=org.apache.log4j.FileAppender
#配置文件輸出樣式
log4j.appender.appender1.layout = org.apache.log4j.PatternLayout
log4j.appender.appender1.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
#指定僅記錄ERROR以上級別的日志
log4j.appender.appender1.Threshold = ERROR
log4j.appender.appender1.ImmediateFlush = TRUE
#指定將日志累加到日志文件末尾
log4j.appender.appender1.Append = TRUE
#指定日志文件
log4j.appender.appender1.File = ./Common-logging-Modle/log/error.log
log4j.appender.appender1.Encoding = UTF-8
④運行代碼不變矢门,結(jié)果如下:
error.log
[ERROR][2019/01/31 17:56:13569][com.log.CommonsTest.main(CommonsTest.java:16)]
ERROR ...
總結(jié)
1.盡可能將可配置的內(nèi)容抽離作為配置盆色,而不是在代碼中做更改,可以極大增強系統(tǒng)靈活性
2.common-logging的日志級別分為六個祟剔,默認級別為info隔躲,apache推薦使用四個級別:ERROR、WARN物延、INFO宣旱、DEBUG
3.common-logging的關鍵類log有5個基本實現(xiàn)類,分別是org.apache.commons.logging.impl.Jdk14Logger叛薯,org.apache.commons.logging.impl.Log4JLogger浑吟,org.apache.commons.logging.impl.LogKitLogger笙纤,org.apache.commons.logging.impl.SimpleLog,org.apache.commons.logging.impl.NoOpLog
4.LogFactory使用動態(tài)查找機制進行日志實例化组力,執(zhí)行順序為:common-logging.properties---->系統(tǒng)環(huán)境變量------->log4j--->jul--->simplelog---->nooplog
參考文檔:
【1】官方文檔