slf4j?jcl?jul?log4j1?log4j2?logback各組件系統(tǒng)日志切換
系列文章已完成,目錄如下:
jdk-logging log4j logback日志系統(tǒng)實現(xiàn)機制原理介紹
commons-logging與jdk-logging、log4j1、log4j2、logback的集成原理
slf4j與jul、log4j1、log4j2、logback的集成原理
各種jar包總結
log4j1
:
log4j:log4j1的全部內容
log4j2
:
log4j-api:log4j2定義的API
log4j-core:log4j2上述API的實現(xiàn)
logback
:
logback-core:logback的核心包
logback-classic:logback實現(xiàn)了slf4j的API
commons-logging
:
commons-logging:commons-logging的原生全部內容
log4j-jcl:commons-logging到log4j2的橋梁
jcl-over-slf4j:commons-logging到slf4j的橋梁
slf4j轉向某個實際的日志框架:
場景介紹:如 使用slf4j的API進行編程,底層想使用log4j1來進行實際的日志輸出,這就是slf4j-log4j12干的事。
slf4j-jdk14:slf4j到jdk-logging的橋梁
slf4j-log4j12:slf4j到log4j1的橋梁
log4j-slf4j-impl:slf4j到log4j2的橋梁
logback-classic:slf4j到logback的橋梁
slf4j-jcl:slf4j到commons-logging的橋梁
某個實際的日志框架轉向slf4j:
場景介紹:如 使用log4j1的API進行編程,但是想最終通過logback來進行輸出,所以就需要先將log4j1的日志輸出轉交給slf4j來輸出,slf4j再交給logback來輸出。將log4j1的輸出轉給slf4j,這就是log4j-over-slf4j做的事
這一部分主要用來進行實際的日志框架之間的切換(下文會詳細講解)
jul-to-slf4j:jdk-logging到slf4j的橋梁
log4j-over-slf4j:log4j1到slf4j的橋梁
jcl-over-slf4j:commons-logging到slf4j的橋梁
集成總結
commons-logging與其他日志框架集成
1 commons-logging與jdk-logging集成:
需要的jar包:
commons-logging
2 commons-logging與log4j1集成:
需要的jar包:
commons-logging
log4j
3 commons-logging與log4j2集成:
需要的jar包:
commons-logging
log4j-api
log4j-core
log4j-jcl(集成包)
4 commons-logging與logback集成:
需要的jar包:
logback-core
logback-classic
slf4j-api、jcl-over-slf4j(2個集成包,可以不再需要commons-logging)
5 commons-logging與slf4j集成:
需要的jar包:
jcl-over-slf4j(集成包,不再需要commons-logging)
slf4j-api
slf4j與其他日志框架集成
slf4j與jdk-logging集成:
需要的jar包:
slf4j-api
slf4j-jdk14(集成包)
slf4j與log4j1集成:
需要的jar包:
slf4j-api
log4j
slf4j-log4j12(集成包)
slf4j與log4j2集成:
需要的jar包:
slf4j-api
log4j-api
log4j-core
log4j-slf4j-impl(集成包)
slf4j與logback集成:
需要的jar包:
slf4j-api
logback-core
logback-classic(集成包)
slf4j與commons-logging集成:
需要的jar包:
slf4j-api
commons-logging
slf4j-jcl(集成包)
日志系統(tǒng)之間的切換
log4j無縫切換到logback
1 案例
我們已經(jīng)在代碼中使用了log4j1的API來進行日志的輸出,現(xiàn)在想不更改已有代碼的前提下,使之通過logback來進行實際的日志輸出。
已使用的jar包:
log4j
使用案例:
private static final Logger logger=Logger.getLogger(Log4jTest.class); public static void main(String[] args){ if(logger.isInfoEnabled()){ logger.info("log4j info message"); } }
上述的Logger是log4j1自己的org.apache.log4j.Logger,在上述代碼中,我們在使用log4j1的API進行編程
現(xiàn)在如何能讓上述的日志輸出通過logback來進行輸出呢?
只需要更換一下jar包就可以:
第一步:去掉log4j jar包
第二步:加入以下jar包
log4j-over-slf4j(實現(xiàn)log4j1切換到slf4j)
slf4j-api
logback-core
logback-classic
第三步:在類路徑下加入logback的配置文件
原理是什么呢?
2 切換原理
看下log4j-over-slf4j就一目了然了:
我們可以看到,這里面其實是簡化更改版的log4j。去掉log4j1的原生jar包,換成該簡化更改版的jar包(可以實現(xiàn)無縫遷移)。
但是簡化更改版中的Logger和原生版中的實現(xiàn)就不同了,簡化版中的Logger實現(xiàn)如下(繼承了Category):
public class Category { private String name; protected org.slf4j.Logger slf4jLogger; private org.slf4j.spi.LocationAwareLogger locationAwareLogger; Category(String name) { this.name = name; slf4jLogger = LoggerFactory.getLogger(name); if (slf4jLogger instanceof LocationAwareLogger) { locationAwareLogger = (LocationAwareLogger) slf4jLogger; } } }
從上面可以看到簡化版中的Logger內部是使用slf4j的API來生成的,所以我們使用的簡化版的Logger會委托給slf4j來進行輸出,由于當前類路徑下有l(wèi)ogback-classic,所以slf4j會選擇logback進行輸出。從而實現(xiàn)了log4j到logback的日志切換。
下面的內容就只講解日志系統(tǒng)到slf4j的切換,不再講解slf4j選擇何種日志來輸出
jdk-logging無縫切換到logback
1 案例
private static final Logger logger=Logger.getLogger(JulSlf4jLog4jTest.class.getName()); public static void main(String[] args){ logger.log(Level.INFO,"jul info a msg"); logger.log(Level.WARNING,"jul waring a msg"); }
可以看到上述是使用jdk-logging自帶的API來進行編程的,現(xiàn)在我們想這些日志交給logback來輸出
解決辦法如下:
第一步:加入以下jar包:
jul-to-slf4j (實現(xiàn)jdk-logging切換到slf4j)
slf4j-api
logback-core
logback-classic
第二步:在類路徑下加入logback的配置文件
第三步:在代碼中加入如下代碼:
static{ SLF4JBridgeHandler.install(); }
切換原理
先來看下jul-to-slf4j jar包中的內容:
我們看到只有一個類:SLF4JBridgeHandler
它繼承了jdk-logging中定義的java.util.logging.Handler,Handler是jdk-logging處理日志過程中的一個處理器(具體我也沒仔細研究過),在使用之前,必須要提前注冊這個處理器,即上述的SLF4JBridgeHandler.install()操作,install后我們就可以通過這個handler實現(xiàn)日志的切換工作,如下:
protected Logger getSLF4JLogger(LogRecord record) { String name = record.getLoggerName(); if (name == null) { name = UNKNOWN_LOGGER_NAME; } return LoggerFactory.getLogger(name); }
在處理日志的過程中,使用了slf4j的原生方式LoggerFactory來獲取一個slf4j定義的Logger來進行日志的輸出
而slf4j則又會選擇logback來進行實際的日志輸出
commons-logging切換到logback
使用案例
使用的jar包
commons-logging
案例如下:
private static Log logger=LogFactory.getLog(JulJclTest.class); public static void main(String[] args){ if(logger.isTraceEnabled()){ logger.trace("commons-logging-jcl trace message"); } }
可以看到我們使用commons-logging的API來進行日志的編程操作,現(xiàn)在想切換成logback來進行日志的輸出(這其實就是commons-logging與logback的集成)
解決辦法如下:
第一步:去掉commons-logging jar包(其實去不去都無所謂)
第二步:加入以下jar包:
jcl-over-slf4j(實現(xiàn)commons-logging切換到slf4j)
slf4j-api
logback-core
logback-classic
第三步:在類路徑下加入logback的配置文件
切換原理
這個原理之前都已經(jīng)說過了,可以看下commons-logging與logback的集成
就是commons-logging通過jcl-over-slf4j 來選擇slf4j作為底層的日志輸出對象,而slf4j又選擇logback來作為底層的日志輸出對象。
常用的日志場景切換解釋
上面把日志的切換原理說清楚了,下面就針對具體的例子來進行應用
先來看下slf4j官方的一張圖:
下面分別詳細說明這三個案例
1 左上圖
現(xiàn)狀:
目前的應用程序中已經(jīng)使用了如下混雜方式的API來進行日志的編程:
現(xiàn)在想統(tǒng)一將日志的輸出交給logback
commons-logging
log4j1
jdk-logging
解決辦法:
加入以下jar包:
第一步:將上述日志系統(tǒng)全部無縫先切換到slf4j
- 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
- 去掉log4j1(必須去掉),使用log4j-over-slf4j,將log4j1的日志輸出切換到slf4j
- 使用jul-to-slf4j,將jul的日志輸出切換到slf4j
第二步:使slf4j選擇logback來作為底層日志輸出
slf4j-api
logback-core
logback-classic
下面的2張圖和上面就很類似
2 右上圖
現(xiàn)狀:
目前的應用程序中已經(jīng)使用了如下混雜方式的API來進行日志的編程:
現(xiàn)在想統(tǒng)一將日志的輸出交給log4j1
commons-logging
jdk-logging
解決辦法:
加入以下jar包:
第一步:將上述日志系統(tǒng)全部無縫先切換到slf4j
- 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
- 使用jul-to-slf4j,將jul的日志輸出切換到slf4j
第二步:使slf4j選擇log4j1來作為底層日志輸出
加入以下jar包:
slf4j-api
log4j
slf4j-log4j12(集成包)
3 左下圖
現(xiàn)狀:
目前的應用程序中已經(jīng)使用了如下混雜方式的API來進行日志的編程:
現(xiàn)在想統(tǒng)一將日志的輸出交給jdk-logging
commons-logging
log4j
解決辦法:
第一步:將上述日志系統(tǒng)全部無縫先切換到slf4j
- 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
- 去掉log4j1(必須去掉),使用log4j-over-slf4j,將log4j1的日志輸出切換到slf4j
第二步:使slf4j選擇jdk-logging來作為底層日志輸出
加入以下jar包:
slf4j-api
slf4j-jdk14(集成包)
沖突說明
仍然是這里的內容slf4j官網(wǎng)的沖突說明
其實明白上面介紹的各jar包的作用,就很容易理解
jcl-over-slf4j 與 slf4j-jcl 沖突
jcl-over-slf4j: commons-logging切換到slf4j
slf4j-jcl : slf4j切換到commons-logging
如果這兩者共存的話,必然造成相互委托,造成內存溢出
log4j-over-slf4j 與 slf4j-log4j12 沖突
log4j-over-slf4j : log4j1切換到slf4j
slf4j-log4j12 : slf4j切換到log4j1
如果這兩者共存的話,必然造成相互委托,造成內存溢出。但是log4j-over-slf4內部做了一個判斷,可以防止造成內存溢出:
即判斷slf4j-log4j12 jar包中的org.slf4j.impl.Log4jLoggerFactory是否存在,如果存在則表示沖突了,拋出異常提示用戶要去掉對應的jar包,代碼如下,在slf4j-log4j12 jar包的org.apache.log4j.Log4jLoggerFactory中:
jul-to-slf4j 與 slf4j-jdk14 沖突
jul-to-slf4j : jdk-logging切換到slf4j
slf4j-jdk14 : slf4j切換到jdk-logging
如果這兩者共存的話,必然造成相互委托,造成內存溢出
結束語
至此,這個日志系列就算終于完成了。它注重于日志系統(tǒng)之間的交互與集成,所以想深入研究單個日志系統(tǒng)的架構的話,就需要各位自行去深入研究了,希望大家以后多多支持腳本之家!
相關文章
Java如何實現(xiàn)支付寶電腦支付基于servlet版本
這篇文章主要介紹了Java如何實現(xiàn)支付寶電腦支付基于servlet版本,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11Java實現(xiàn)限定時間CountDownLatch并行場景
本文將結合實例代碼,介紹Java實現(xiàn)限定時間CountDownLatch并行場景,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07詳解springboot+mybatis多數(shù)據(jù)源最簡解決方案
本篇文章主要介紹了詳解springboot+mybatis多數(shù)據(jù)源最簡解決方案,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05快速解決List集合add元素,添加多個對象出現(xiàn)重復的問題
這篇文章主要介紹了快速解決List集合add元素,添加多個對象出現(xiàn)重復的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Java使用@EnableEurekaServer實現(xiàn)自動裝配詳解
這篇文章主要介紹了Java使用@EnableEurekaServer實現(xiàn)自動裝配過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-10-10