天天看點

徹底解決SLF4J的日志沖突的問題

今天公司同僚上線時發現,有的機器列印了日志,而有的機器則一條日志也沒有打。以往都是沒有問題的。

是以猜測是這次開發間接引入新的日志jar包,日志沖突導緻未列印。

排查代碼發現,系統使用的是SLF4J架構列印log4j2的日志。檢視系統中引入的jar包發現果然有多個SLF4J的橋接包。于是排掉沖突jar包,然後上線時所有機器都正常列印日志

先上一張關系圖:SLF4J架構、各種具體日志實作以及相應橋接包的關系圖

徹底解決SLF4J的日志沖突的問題

由于線上系統要接入很多中間件,是以系統中會有各種各樣的日志列印形式(例如:log4j2、JCL、logback等等)。

為了能整合所有日志并進行統一列印,最常用的就是SLF4J架構。

SLF4J架構作為門面架構,并沒有日志的具體實作。而是通過和其他具體日志實作進行關聯轉換,并在系統中配置一種日志實作進行列印。

于是就很容易造成jar包引入沖突,導緻有多個日志實作。當SLF4J架構選擇的日志實作和我們配置的不一緻時,就會列印不出日志。

SLF4J架構發現有多個日志實作時,是會列印提示資訊的。但由于是标準錯誤輸出,會在控制台(Tomcat的catalina.out)中列印【當業務日志檔案中沒有日志列印時,可以檢視catalina.out是否有提示】

徹底解決SLF4J的日志沖突的問題
徹底解決SLF4J的日志沖突的問題

因為每個SLF4J的橋接包都有org.slf4j.impl.StaticLoggerBinder

SLF4J則會随機選擇一個使用。當選擇的跟系統配置的一樣時就可以列印日志,否則就列印不出。

徹底解決SLF4J的日志沖突的問題

如上圖所示findPossibleStaticLoggerBinderPathSet方法,當有多個日志橋接包時會傳回一個Set集合且提示一條資訊。

由于這個資訊提示并不強烈,不易感覺。我們可以根據這一點,使用反射來擷取到系統中實際的橋接包數量,并做自定義的提示。

1、實作spring的BeanFactoryPostProcessor,并将其交由spring管理。保證系統啟動後,自動進行日志沖突校驗 2、使用反射擷取LoggerFactory的執行個體以及findPossibleStaticLoggerBinderPathSet方法的傳回結果 3、根據橋接包數量判斷是否異常,進行自定義報警 4、根據報警資訊,進行排包

上面的方式也隻是幫助我們快速感覺到日志jar包沖突,仍需手動排包。

是否存在一種解決方法,能幫忙我們徹底解決這種問題呢?

答案是有

即将我們需要引入的jar包和需要排掉的jar包聲明到maven的最上層,将需要排掉的包聲明為provided即可

這種方案是利用maven的掃包政策: 1、依賴最短路徑優先原則; 2、依賴路徑相同時,申明順序優先原則

當我們将所有jar包聲明為直接依賴後,會優先被使用。

而我們需要排掉的包隻要聲明為provided,就不會打入包中。

進而實作需要的包以我們聲明的為準,需要排掉的包也不會被間接依賴影響

第三步的方案:啟動時感覺系統是否存在日志jar包沖突,沖突後手動排包

第四步的方案:一次聲明所需的所有日志jar包配置,無需在擔心沖突問題

------The End------

如果這個辦法對您有用,或者您希望持續關注,也可以掃描下方二維碼或者在微信公衆号中搜尋【碼路無涯】