【精品】解釋JAVA五花八門的各種日誌系統及關係,

 

目錄

前言:

分類

介紹

javaLog

log4j

logback

Nop

slf4j

jcl

問答:

1.如果slf4j裏引入了多種連接器和底層實現.那麼真正執行的是誰?

2.項目日誌包只加載這些,且沒有配置文件,請問Spring的debug運行日誌會顯示出來嗎?底層實現是哪個日誌系統?

3.我們講slf4j時那個連接器圖裏,還有個slf4j-jcl的連接器的jar,那個是將jcl作爲slfj的底層實現的連接器,和jcl-over-slf4j.jar作用正好相反,如果將該jar投入到第二題環境裏面。然後將logback-classic.jar刪除掉,則會發生什麼事情?會不會發生slf4j和jcl循環調用最終導致棧溢出呢?

4.有些依賴源碼裏直接使用的log4j,而我現在希望由slf4j+logback來控制所有的日誌怎麼辦?

最優使用

結語:


前言:

 

編寫目的如果你覺得你的項目裏日誌系統像不同動物的屎一樣混在一起,那麼這篇文章是你所需要的

閱讀要求本文的讀者要求至少使用過一段時間日誌系統。對於沒有使用過的,不建議你看。

其他:歡迎轉載,但請註明出處。

分類

目前JAVA流行的日誌系統有

Java.util.Logger 以後簡稱javaLog
log4j
logback
NOPlogger,以後簡稱Nop
slf4j
common-logger 以後簡稱jcl

介紹

以上6個日誌系統,其中slf4j和jcl是接口是規則,相當於jdbc,其他4個是具體實現。

也就是說如果只引入了slf4j和jcl,那麼日誌系統是根本沒有卵用的。

但是你可以不引入slf4j和jcl,而只引入其他實現,那麼實現日誌是可以的。(除了logback)

接下來逐一介紹。

javaLog

這個是JDK1.4的時候增加的日誌類。使用起來很簡單。看代碼,內容很簡單,打印了兩行

import java.util.logging.Logger;

public class JDKLog {
	public static void main(String[] args) {
		Logger logger = Logger.getLogger("aaaa");
		System.out.println(logger.getLevel());//獲取當前Log的等級
		logger.info("111111");
		logger.info("22222");
	}
}

再看下現象,這個現象很有趣,所以要截圖。

如果你用過tomcat,就知道這裏的打印信息和tomcat默認打印的信息簡直一摸一樣。說明tomcat默認使用的就是JavaLog,只是日誌等級默認卻是null。

javalog使用好的話比較麻煩且基本概念落伍。

log4j

apache組織的日誌系統。是最火爆的,看下如何使用

import org.apache.log4j.Logger;

public class Log4jLog {
	public static void main(String[] args) {
		Logger logger = Logger.getLogger(Log4jLog.class);
		logger.info("Log4j");
		
	}
}

 如果只是這樣的話,那麼絕對打印不了內容,只會打印紅色的警告提示,因爲對於Log4j來說,配置文件是必須的。

你可以加上一個log4j.properties,然後再打印就打出來了。

logback

logback是一個log4j作者二次開發的一個更爲高效快速的日誌系統。但是它不能單獨使用,因爲它沒有入口,你必須使用接口來使用它,比如slf4j或者jcl

我們接下來用slf4j來看logback如何使用的,你需要這樣作。

引入且只引入以下三個包:slf4j - api.jarlogback - core.jar 和logback - classic.jar。(不要混有其他日誌包,原因在slf4j裏面講。)

然後代碼這樣寫,先不要運行。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogBackLog {
	public static void main(String[] args) {
		Logger logger = LoggerFactory.getLogger(LogBackLog.class);
		logger.info("aaaaaaaa");
		System.out.println(logger.getClass());
	}
}

如果你能認真一些,就能發現這個測試類裏並沒有引入logback的類,很奇怪的事情!不過還有更奇怪的事情,接下來請你運行。

18:06:08.894 [main] INFO com.bai.momo.LogBackLog - aaaaaaaa
class ch.qos.logback.classic.Logger

打印了日誌,而且打印了logger的className,竟然從org.slf4j.Logger變成了 class ch.qos.logback.classic.Logger。

原因暫時不說,在slf4j裏面講。

現在你還有更需要注意的事情!

請把代碼裏的logger.info改爲logger.debug,再次運行。

你會發現日誌還是打印了。如果你瞭解一些關於日誌級別的有關信息,那麼你應該知道本例中的logger的級別就是DEBUG級別,否則打印不出來。

原因在於:logback會先去尋找配置文件logback-test.xmllogback.xml,如果沒有找到,則會使用ch.qos.logback.core.ConsoleAppender這個默認的控制檯輸出配置。而logback的根記錄器的級別默認是DEBUG。

如果你遇到過控制檯debug日誌無腦刷出,什麼都控制不了,那麼原因就在於此。那麼請配置一個logback.xml來修改格式或者級別即可。一個簡單的info級別的logback.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
    debug="false" scan="true" scanPeriod="30 second">
    
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    	<encoder charset="utf-8">
           <pattern>%n%-6p %m %n</pattern>
        </encoder>
    </appender>    
    <root level="INFO">
       <appender-ref ref="STDOUT" />
    </root>
 </configuration>

Nop

Nop就是靜默處理,就是什麼都不幹。愛咋咋滴,也不打印也不輸出。

你可以找任意一款NopLogger.java的源碼,就會發現它裏面都是空的。

Nop的作用是什麼?在slf4j裏說。

slf4j

重頭戲到了。

slf4j是簡單日誌門面,它不提供具體的實現,只是它有和其他日誌之間的連接器,姑且就叫做連接器吧。如下圖:

先不看JCL.先看藍色和綠色。

slf4j如果底層使用javaLog,需要slf4-jdk.jar

slf4如果底層使用log4j,需要使用slf4-log4j.jar

slf4如果底層使用logback,需要使用logback-classic.jar

而slf4j的核心jar包是slf4j - api.jar。

那麼如果你想使用slf4j,請先導入slf4j - api.jar,然後選擇其中一個底層日誌系統,引入其包以及連接器的jar包。接着如下使用即可。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogBackLog {
	public static void main(String[] args) {
		Logger logger = LoggerFactory.getLogger(LogBackLog.class);
		logger.info("aaaaaaaa");
		System.out.println(logger.getClass());
	}
}

這個代碼片和上面講logback的代碼片一摸一樣。這就是接口的魅力,如果你想更換底層日誌系統,只需要更換底層日誌包和連接器包即可。

自動搜尋底層日誌系統的原理就是:其實每一個連接器裏都有一個org.slf4j.impl.StaticLoggerBinder這個類,是相同的包相同的類哦。slf4j會自動搜索類路徑下的org.slf4j.impl.StaticLoggerBinder,如果搜到了某個org.slf4j.impl.StaticLoggerBinder,就加載該StaticLoggerBinder所處的連接器,使用該連接器裏所默認的底層日誌系統。

注意以下幾點:

1.如果你只引入了slf4j - api.jar,而不引入底層實現或連接器,那麼運行上面的代碼將不會打印日誌,而log.getClass的結果是NopLogger,Nop作用就是這樣,既然我不知道咋辦,那我就啥都不幹。

2.如果你更換了底層實現或連接器,那麼logger,getClass將會改變,因爲具體實現已經改變。

3.如果你更換成了log4j或者logback,請附帶上她們的log4j.properties或logback.xml。

4.如果你引入了多種底層實現或連接器,那個現象,呵呵了~~~~~~解釋一下,slf4j是嚴格不推薦你這樣做的,但是現在的系統都有各種依賴,而依賴裏的日誌系統又不盡相同,所以有時我們也沒有辦法。該怎麼做呢?請看問答

jcl

指的是org.apache.common-logging.jar包。

是apache早期的項目,2000年左右的時候就有了,期間也更新過幾次。

它也是個日誌的門面系統,同樣的也有連接器,但最重要的是它的配置文件,說到這裏,有同學可能會奇怪,爲什麼我一直在用common-logging.jar,而不需要配置文件,卻能照樣打印使用啊?

說來話長,請看jcl目前的搜索底層日誌實現的執行流程,以下流程,順序執行,如果匹配,則立即終止:

1.查找配置文件commons-logging.properties。如果有,看裏面配置了什麼底層實現。

2.查找System.getProperties("org.apache.commons.logging.LogFactory"),如果不是null,看結果代表了什麼底層實現.

3.查找所有jar包的註冊信息,如果裏面有META-INF/services/org.apache.commons.logging.LogFactory這個文件,讀取該文件的第一行即是配置了底層實現.

4.如果有log4j.jar.則設置爲log4j爲底層實現

5.如果是java1.4以後,則設置爲javaLog

6.使用自帶的默認的SimpleLog

而我們平時使用jcl一般都是配合Log4j使用,都是到了第四步終止。

而且即使沒有log4j,還有第五步使用javaLog呢!所以使用JCL時完全不用擔心的。

第三步則是jcl連接器的事情,如果有連接器,那麼log4j就沒有用了。

問答:

1.如果slf4j裏引入了多種連接器和底層實現.那麼真正執行的是誰?

我只知道現象,哪個連接器先加載,就執行誰.因爲slf4j搜索連接器會搜索所有的連接器,然後放到一個數組裏.但是好像默認取數組[0]作爲真正的日誌實現.

2.項目日誌包只加載這些,且沒有配置文件,請問Spring的debug運行日誌會顯示出來嗎?底層實現是哪個日誌系統?

slf4j - api.jar,

common-logging.jar,

log4j.jar,

logback-core.jar,

logback-classic.jar,

jcl-over-slf4j.jar

debug日誌會顯示出來,底層是logback

原因是:spring使用jcl作爲日誌門面,jcl會按照搜索順序,在第三步停止,因爲jcl-over-slf4j.jar是將slfj作爲jcl的底層實現d的連接器,而slf4j啓動起來也會搜索真正的底層實現,所以最終只搜到了logback的連接器(缺少log4到slf4j的連接器)。而logback.xml沒有配置出來,所以會使用默認的控制檯打印且默認級別是debug.

實際上就有了一種橋接的作用.

3.我們講slf4j時那個連接器圖裏,還有個slf4j-jcl的連接器的jar,那個是將jcl作爲slfj的底層實現的連接器,和jcl-over-slf4j.jar作用正好相反,如果將該jar投入到第二題環境裏面。然後將logback-classic.jar刪除掉,則會發生什麼事情?會不會發生slf4j和jcl循環調用最終導致棧溢出呢?

自己去試試吧!

4.有些依賴源碼裏直接使用的log4j,而我現在希望由slf4j+logback來控制所有的日誌怎麼辦?

jcl-over-slf4j.jar是jcl橋接到slf4j的.

log4j-over-slf4j.jar是log4j橋接到Slf4j裏面的.

當然也有javaLog橋接到Slf4裏面的.

切記使用這種模式的時候,小心自循環調用.

最優使用

強烈推薦slf4j作爲門面,然後使用logback作爲底層實現,因爲logback十分高效,當然你可以隨時切換底層實現。

由於一些依賴使用了jcl,那麼請添加jcl-over-slf4j.jar,將jcl的日誌系統實際上由slf4j把控。

結語:

寫作原因是因爲自己的項目裏引入多種依賴,導致日誌系統各種靈異事件,網上教程,也都是讀起來無味之極,索性便花了兩天略讀源碼,又去官網看文檔,大抵才瞭解一些。

寫了4個半小時,酣暢淋漓。

煎炒烹炸,盛盤出來,以饗諸君。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章