作者:Alben's home
來源:https://albenw.github.io/posts/854fc091/
概要
本文的目的是搞清楚Java中各種日誌Log之間是怎麼的關係,如何作用、依賴,好讓我們平時在工作中如果遇到“日誌打不出”或者“日誌jar包衝突”等之類的問題知道該如何入手解決,以及在各種場景下如何調整項目中的各個框架的日誌輸出,使得輸出統一。
Log日誌體系
在日常工作中我們可能看到項目中依賴的跟日誌相關的jar包有很多,commons-logging.jar
、log4j.jar
、sl4j-api.jar
、logback.jar
等等,眼花繚亂。我們要正確的配置,使得jar包相互作用生效之前,就先要理清它們之間的關係。
背景/發展史
那就要從Java Log的發展歷程開始說起。
log4j
(作者Ceki Gülcü)出來時就等到了廣泛的應用(注意這裏是直接使用),是Java日誌事實上的標準,併成爲了Apache的項目Apache要求把log4j併入到JDK,SUN拒絕,並在jdk1.4版本後增加了
JUL
(java.util.logging
)畢竟是JDK自帶的,JUL也有很多人用。同時還有其他日誌組件,如SimpleLog等。這時如果有人想換成其他日誌組件,如log4j換成JUL,因爲api完全不同,就需要改動代碼。
Apache見此,開發了
JCL
(Jakarta Commons Logging),即commons-logging-xx.jar
。它只提供一套通用的日誌接口api,並不提供日誌的實現。很好的設計原則嘛,依賴抽象而非實現。這樣應用程序可以在運行時選擇自己想要的日誌實現組件。這樣看上去也挺美好的,但是log4j的作者覺得JCL不好用,自己開發出
slf4j
,它跟JCL類似,本身不替供日誌具體實現,只對外提供接口或門面。目的就是爲了替代JCL。同時,還開發出logback
,一個比log4j擁有更高性能的組件,目的是爲了替代log4j。Apache參考了logback,並做了一系列優化,推出了
log4j2
關係/依賴
大概瞭解心路歷程後,再詳細看看它們之間的關係、依賴。
JCL
commons-logging
已經停止更新,最後的狀態如下所示:
JCL支持日誌組件不多,不過也有很人用的,例如Spring 現在用的也越來越少了,也不多講了
SLF4J
因爲當時Java的日誌組件比較混亂繁雜,Ceki Gülcü推出slf4j後,也相應爲行業中各個主流日誌組件推出了slf4j的適配 圖來源於官方文檔
圖的意思爲如果你想用slf4j作爲日誌門面的話,你如何去配合使用其他日誌實現組件,這裏說明一下(注意jar包名缺少了版本號,在找版本時也要注意版本之間是否兼容)
slf4j + logback
slf4j-api.jar
+logback-classic.jar
+logback-core.jar
slf4j + log4j
slf4j-api.jar
+slf4j-log4j12.jar
+log4j.jar
slf4j + jul
slf4j-api.jar
+slf4j-jdk14.jar
也可以只用slf4j無日誌實現
slf4j-api.jar
+slf4j-nop.jar
SLF4J的適配
slf4j支持各種適配,無論你現在是用哪種日誌組件,你都可以通過slf4j的適配器來使用上slf4j。只要你切換到了slf4j,那麼再通過slf4j用上實現組件,即上面說的。圖來源於官方文檔
其實總的來說,無論就是以下幾種情況
你在用JCL 使用
jcl-over-slf4j.jar
適配你在用log4j 使用
log4j-over-slf4j.jar
適配你在用JUL 使用
jul-to-slf4j.jar
適配
我在網上盜一張圖,給大家一個整體的依賴圖(懶得畫了)
讓Spring統一輸出
這就是爲了對slf4j的適配做一個例子說明。Spring是用JCL作爲日誌門面的,那我們的應用是slf4j + logback,怎麼讓Spring也用到logback作爲日誌輸出呢?這樣的好處就是我們可以統一項目內的其他模塊、框架的日誌輸出(日誌格式,日誌文件,存放路徑等,以及其他slf4j支持的功能) 很簡單,就是加入jcl-over-slf4j.jar
就好了。我又盜了一個圖來說明
適配思路
其實很簡單
你首先確認需要統一日誌的模塊、框架是使用哪個日誌組件的,然後再找到sfl4j的適配器。
記得去掉無用的日誌實現組件,只保留你要用的。
常見問題
slf4j的日誌加載會在程序啓動時把日誌打出來,所以一定要注意,它會說明加載是否成功,加載了那個日誌實現。slf4j已經對錯誤作了說明官網說明下面講一下可能經常遇到的問題
Failed to load class org.slf4j.impl.StaticLoggerBinder
沒找到日誌實現,如果你覺得你已經寫上了對應的日誌實現依賴了,那你要檢查一下了,一般來說極有可能是版本不兼容。
Multiple bindings
找到多個日誌實現,slf4j會找其中一個作爲日誌實現。
代碼規範
阿里對此的代碼規範:
“【強制】應用中不可直接使用日誌系統(Log4j、Logback)中的 API,而應依賴使用日誌框架 SLF4J 中的 API,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。import org.slf4j.Logger; import org.slf4j.LoggerFactory; private static final Logger logger = LoggerFactory.getLogger(Abc.class);
”
總結
文章幫大家梳理了Java日誌組件的關係,以及如何解決日常中常見日誌相關的問題,希望對大家幫助。