java日志篇(4)-common-logging

慢慢來比較快,虛心學技術

前言:Jakarta Commons-logging(JCL)是apache最早提供的日志的門面接口。它將一些具體的日志組件抽象為接口,實現日志操作的解耦和可插拔,讓眾多的日志工具有一個共同的操作方式

一、common-logging簡單使用示例

①引入common-logging的jar包,最新jar包從官方網站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目錄下,配置內容如下

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

運行輸出結果:

[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...

如上實現第一個簡單的common-logging程序,引發(fā)以下幾個問題

問題一:common-logging.properties屬性文件中的org.apache.commons.logging.Log和它的值代表了什么?

問題二:為什么明明代碼中寫了logger.trace和logger.debug,卻沒有輸出?

問題三:LogFactory的實現原理是什么?

帶著問題去思考學習,效率總是最高的

二、問題探索

1.org.apache.commons.logging.Log

JCL有兩個基本的抽象類: Log( 基本記錄器 ) 和 LogFactory( 負責創(chuàng)建 Log 實例 ),其中,Log有多個默認實現類,分別是:

-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自帶日志實現類。它實現了Log接口,把日志消息都輸出到系統(tǒng)錯誤流System.err 中。
-org.apache.commons.logging.impl.NoOpLog common-logging自帶日志實現類。它實現了Log接口。 其輸出日志的方法中不進行任何操作。

在common-logging.properties中配置的org.apache.commons.logging.Log參數指定了common-logging將使用哪種日志實現,這也是前言所說的,通過配置實現日志組件的可插拔和解耦,極大增加了靈活性

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 運行時產生的有意義的事件。期望這類信息能立即顯示在狀態(tài)控制臺上。

5)debug 系統(tǒng)流程中的細節(jié)信息。期望這類信息僅被寫入log文件中。

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

apache建議使用4級,即 ERRORWARN、INFO、DEBUG

而當我們在common-logging.properties配置使用的是SimpleLog日志實現,該日志實現默認日志級別是info,所以才會出現簡單實例中的輸出結果,如何更改SimpleLog的日志級別?

創(chuàng)建simplelog.properties配置文件,放到classpath下,如果是maven則放到src/main/resource目錄下,配置內容參考:

org.apache.commons.logging.simplelog.defaultlog=TRACE

配置后結果輸出如下(bingo):

[TRACE] CommonsTest - TRACE...
[DEBUG] CommonsTest - DEBUG ...
[INFO] CommonsTest - INFO ...
[ERROR] CommonsTest - ERROR ...
[WARN] CommonsTest - WARN...

3.LogFactory實現原理

LogFactory作為log的工廠存在,使用動態(tài)查找機制進行l(wèi)og實例的獲取,具體執(zhí)行步驟如下:

①首先在classpath下尋找commons-logging.properties文件。如果找到,則使用其中定義的Log實現類;如果找不到,則在查找是否已定義系統(tǒng)環(huán)境變量org.apache.commons.logging.Log,找到則使用其定義的Log實現類;

②查看classpath中是否有Log4j的包,如果發(fā)現,則自動使用Log4j作為日志實現類;

③使用JDK自身的日志實現類(JDK1.4以后才有日志實現類);

④使用commons-logging自己提供的一個簡單的日志實現類SimpleLog;

上述步驟當LogFactory成功找到一個日志實現之后就會停止

實際上,看源碼發(fā)現,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字符串數組獲取日志實例(動態(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包從官方網站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

④運行代碼不變,結果如下:

error.log

[ERROR][2019/01/31 17:56:13569][com.log.CommonsTest.main(CommonsTest.java:16)]
ERROR ...

總結

1.盡可能將可配置的內容抽離作為配置,而不是在代碼中做更改,可以極大增強系統(tǒng)靈活性

2.common-logging的日志級別分為六個,默認級別為info,apache推薦使用四個級別:ERROR、WARNINFO、DEBUG

3.common-logging的關鍵類log有5個基本實現類,分別是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】官方文檔

【2】https://blog.csdn.net/backbug/article/details/78655664

【3】http://www.itdecent.cn/p/b818d9d26d39

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容