004-log-common-logging,Apache整合日誌框架JCL門面框架、JCL+log4j

1、概述

  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

1.一、pom依賴

<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

1.二、配置

  建立commons-logging.properties文件,將其放在classpath下,若是是maven項目則將其放在src/main/resource目錄下,配置內容以下git

org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

1.三、使用

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."); } }

2、詳細說明

    

2.一、LogFactory獲取相對應的Log實現類邏輯

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

2.二、日誌級別

1)fatal 很是嚴重的錯誤,致使系統停止。指望這類信息能當即顯示在狀態控制檯上。框架

2)error 其它運行期錯誤或不是預期的條件。指望這類信息能當即顯示在狀態控制檯上。maven

3)warn 使用了不同意使用的API、很是拙劣使用API, '幾乎就是'錯誤, 其它運行時不合須要和不合預期的狀態但還不必稱爲 "錯誤"。指望這類信息能當即顯示在狀態控制檯上。ide

4)info 運行時產生的有意義的事件。指望這類信息能當即顯示在狀態控制檯上。

5)debug 系統流程中的細節信息。指望這類信息僅被寫入log文件中。

6)trace 更加細節的信息。指望這類信息僅被寫入log文件中。

如上述配置了SimpleLog,增長simplelog.properties配置文件,放到classpath下,若是是maven則放到src/main/resource目錄下,配置內容參考:
org.apache.commons.logging.simplelog.defaultlog=TRACE

2.三、LogFactory實現原理

  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; } }

3、common-logging+log4j應用

3.一、POM依賴

<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>

3.二、配置文件

  在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
View Code

3.二、java代碼依舊使用logging代碼便可

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.
相關文章
相關標籤/搜索