Jakarta Commons Logging (JCL)提供的是一個日誌(Log)接口(interface),同時兼顧輕量級和不依賴於具體的日誌實現工具。它提供給中間件/日誌工具開發者一個簡單的日誌操做抽象,容許程序開發人員使用不一樣的具體日誌實現工具。用戶被假定已熟悉某種日誌實現工具的更高級別的細節。JCL提供的接口,對其它一些日誌工具,包括Log4J, Avalon LogKit, and JDK 1.4等,進行了簡單的包裝,此接口更接近於Log4J和LogKit的實現。html
在Logging系統中,目前框架都是基於相同的設計,即從一個LogFactory中取得一個命名的Log(Logger)實例,而後使用這個Log(Logger)實例打印debug、info、warn、error等不一樣級別的日誌。做爲兩個門面日誌系統,Commons Logging和SLF4J也一樣採用這樣的設計。
所謂門面日誌系統,是指它們自己並不實現具體的日誌打印邏輯,它們只是做爲一個代理系統,接收應用程序的日誌打印請求,而後根據當前環境和配置,選取一個具體的日誌實現系統,將真正的打印邏輯交給具體的日誌實現系統,從而實現應用程序日誌系統的「可插拔」,便可以經過配置或更換jar包來方便的更換底層日誌實現系統,而不須要改變任何代碼。我的感受SLF4J的實現更加靈活,而且它還提供了Maker和MDC的接口。java
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
建立commons-logging.properties文件,將其放在classpath下,若是是maven項目則將其放在src/main/resource目錄下,配置內容以下git
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ApplicationMain { private static Log logger = LogFactory.getLog(ApplicationMain.class); public static void main(String[] args) { System.out.println(logger.getClass().getName()); // 記錄debug級別的信息 logger.debug("This is debug message."); // 記錄info級別的信息 logger.info("This is info message."); // 記錄error級別的信息 logger.error("This is error message."); } }
JCL有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責建立Log實例)。當commons-logging.jar被加入到 CLASSPATH以後,它會合理地猜想你想用的日誌工具,而後進行自我設置,用戶根本不須要作任何設置。默認的LogFactory是按照下列的步驟去發現並決定那個日誌工具將被使用的(按照順序,尋找過程會在找到第一個工具時停止):
1. 尋找當前factory中名叫org.apache.commons.logging.Log
配置屬性的值
2. 尋找系統中屬性中名叫org.apache.commons.logging.Log
的值
3. 若是應用程序的classpath中有log4j,則使用相關的包裝(wrapper)類(Log4JLogger)
4. 若是存在Lumberjack版本的Logging系統,則使用Jdk13LumberjackLogger類。
5. 若是應用程序運行在jdk1.4的系統中,使用相關的包裝類(Jdk14Logger)
6. 使用簡易日誌包裝類(SimpleLog)
7. 以上步驟都失敗,則拋出LogConfigurationException。github
LogFactory使用動態查找機制進行日誌實例化,執行順序爲:common-logging.properties---->系統環境變量------->log4j--->jul--->simplelog---->nooplogapache
org.apache.commons.logging.Log的具體實現:數組
org.apache.commons.logging.Log
的具體實現有以下:
- org.apache.commons.logging.impl.Jdk14Logger
使用JDK1.4。
- org.apache.commons.logging.impl.Log4JLogger
使用Log4J。
- org.apache.commons.logging.impl.LogKitLogger
使用 avalon-Logkit。
- org.apache.commons.logging.impl.SimpleLog
common-logging自帶日誌實現類。它實現了Log接口,把日誌消息都輸出到系統錯誤流System.err 中。
- org.apache.commons.logging.impl.NoOpLog
common-logging自帶日誌實現類。它實現了Log接口。 其輸出日誌的方法中不進行任何操做。app
1)fatal 很是嚴重的錯誤,致使系統停止。指望這類信息能當即顯示在狀態控制檯上。框架
2)error 其它運行期錯誤或不是預期的條件。指望這類信息能當即顯示在狀態控制檯上。maven
3)warn 使用了不同意使用的API、很是拙劣使用API, '幾乎就是'錯誤, 其它運行時不合須要和不合預期的狀態但還不必稱爲 "錯誤"。指望這類信息能當即顯示在狀態控制檯上。ide
4)info 運行時產生的有意義的事件。指望這類信息能當即顯示在狀態控制檯上。
5)debug 系統流程中的細節信息。指望這類信息僅被寫入log文件中。
6)trace 更加細節的信息。指望這類信息僅被寫入log文件中。
org.apache.commons.logging.simplelog.defaultlog=TRACE
LogFactory做爲log的工廠存在,使用動態查找機制進行log實例的獲取,具體執行步驟以下:
①首先在classpath下尋找commons-logging.properties文件。若是找到,則使用其中定義的Log實現類;若是找不到,則在查找是否已定義系統環境變量org.apache.commons.logging.Log,找到則使用其定義的Log實現類;
②查看classpath中是否有Log4j的包,若是發現,則自動使用Log4j做爲日誌實現類;
③使用JDK自身的日誌實現類(JDK1.4之後纔有日誌實現類);
④使用commons-logging本身提供的一個簡單的日誌實現類SimpleLog;
上述步驟當LogFactory成功找到一個日誌實現以後就會中止
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字符串數組 if (isDiagnosticsEnabled()) { this.logDiagnostic("No user-specified Log implementation; performing discovery using the standard supported logging implementations..."); } //遍歷classesToDiscover字符串數組獲取日誌實例(動態查找機制) 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; } }
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
在commons-logging.properties文件,將log指向log4j,能夠不加由於默認的,沒有的話會先加載log4j
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
配置log4j.properties配置【能夠參看002-log-log4j】
### 設置### log4j.rootLogger = debug,stdout,D,E ### 輸出信息到控制擡 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n ### 輸出DEBUG 級別以上的日誌到 ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### 輸出ERROR 級別以上的日誌到error.log ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ApplicationMain { private static Log logger = LogFactory.getLog(ApplicationMain.class); public static void main(String[] args) { System.out.println(logger.getClass().getName()); // 記錄debug級別的信息 logger.debug("This is debug message."); // 記錄info級別的信息 logger.info("This is info message."); // 記錄error級別的信息 logger.error("This is error message."); } }
輸出
org.apache.commons.logging.impl.Log4JLogger [DEBUG] 2019-06-21 14:07:37,823 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:13) This is debug message. [INFO ] 2019-06-21 14:07:37,826 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:15) This is info message. [ERROR] 2019-06-21 14:07:37,826 method:com.github.bjlhx15.common.study.log.ApplicationMain.main(ApplicationMain.java:17) This is error message.