1. 程式人生 > >《SLF4J官方文件》SLF4J警告或錯誤資訊及其含義

《SLF4J官方文件》SLF4J警告或錯誤資訊及其含義

原文地址

呼叫方法o.a.commons.logging.impl.SLF4FLogFactory.release

已給出的公用日誌API(common-logging API),實際上是由SLF4J實現的,o.a.commons.logging.impl.SLF4FLogFactory.release方法永遠不會被呼叫。然而,取決於commons-logging.jar在伺服器小程式容器的部署,release()方法可能意外地通過commons-logging.jar裝載的org.apache.commons.logging.LogFactoryl類被呼叫。

當Tomac安裝後,$TOMAC_HOME代表目錄;在最近的Tomac版本上,這是個普遍的現象,尤其當你在應用中在WEB-INF/lib

下放置jcl-over-slf4j.jar而不是在$TOMCAT_HOME/common/lib下放置jar包。為了完全獲得jcl-over-slf4j.jar包的穩定性,我們建議你在$TOMCAT_HOME/common/lib目錄下放置jcl-over-slf4j.jar包,沒有在你的web應用裡放置副本。

jcl-over-slf4j不支援的[某個]操作

當呼叫JCL1.1中受保護的方法,會丟擲不支援操作異常 (UnsupportedOperationException)。這些方法都是通過commons-logging.jarLogFactory 實現呼叫。 當然,LogFactoryjcl-over-slf4j.jar

包下的SLF4FLogFactory實現,SLF4FLogFactory不呼叫這些方法。

如果你研究這個問題,很大可能是你的commons-logging.jar副本在類的路徑下覆蓋了jcl-over-slf4j.jar包中的類。

當呼叫o.a.commons.logging.impl.SLF4FLogFactory.release()方法時,注意實際上這個問題跟發出的警告是非常相似的,已在前一個章節討論了。

日誌名稱不匹配檢測

只有slf4j.detectLoggerNameMismatch系統屬性設定為true時,日誌名稱不匹配警告才會列印。預設情況下,這個屬性沒有設定,即使在日誌名稱不匹配的情況下也不會列印警告。

從1.7.9開始,在指定名稱的日誌器下,向LoggerFactory.getLogger(Class)方法傳參,警告資訊就會被列印,這個方法和SLF4J內部推斷的呼叫者的名稱不同。

例如,程式碼塊如下:

package com.acme;
import com.foo.Kangaroo;

class <strong>Fruit</strong> {
Logger logger = LoggerFactory.getLogger(Kangaroo.class);
}

結果將會顯示:

SLF4J: Detected logger name mismatch. Given name:

"com.foo.Kangaroo"; computed name: "com.acme.Fruit".

但只在slf4j.detectLoggerNameMismatch系統屬性設定為true時才顯示。

當日志器中傳入的引數類是一個基類,這種特定情況下子類不會出現任何警告資訊,例如:

class A {
Logger logger = LoggerFactory.getLogger(getClass());
}
class B extends A {
// no mismatch warning will be issued when B is instantiated
// given that class A is a super-type of class B
}

如果你遇到不能解釋的不匹配警告,你可以用白色大象標記它,當定義了日誌器,這種不能正確推斷出類名的情況是非常少的。我們也很有興趣去獲得這些類。如果你標記了一個無法解釋的不匹配資訊,請給我們發一個[日誌報告]( http://www.slf4j.org/bug-reporting.html)檔案。

載入org.slf4j.impl.StaticLoggerBinder類失敗

當org.slf4j.impl.StaticLoggerBinder類不能從記憶體中載入是,將會報告這個錯誤資訊。當在類路徑中沒有合適的SLF4J繫結時,這種情況會發生。放置一個jar包(只能放其中的一個):slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar, logback-classic.jar。在類路徑中放置一個就可以解決問題。

從1.6.0: 1.6版本的SLF4J,沒有繫結,SLF4J預設是一個無操作日誌實現。

你可以從專案下載頁(http://www.slf4j.org/download.html)下載SLF4J繫結。

在類路徑下發現多個繫結

SLF4J被設計成依次與每個且只有一個基本日誌框架繫結。如果在類路徑下存在不止一個繫結。SLF4J將發出一個警告,列出這些繫結的位置。

當多個繫結在類路徑下,只能選取一個你想用的繫結,移除其他繫結。比如,如果在類路徑下同時有slf4j-simple-1.7.19.jar和 slf4j-nop-1.7.19.jar,你想用無操作繫結,那麼把slf4j-nop-1.7.19.jar從類路徑中移除。

這個SLF4J提供的警告資訊位置列表 為識別過渡新增到專案中不想要的SLF4J繫結依賴包 提供了有效的資訊。在專案中pom.xml檔案中,剔除掉那些隨意宣告的依賴包下的SLF4J繫結。例如,cassandra-all版本0.0.1同時把log4jslf4j-log4j12宣告為編譯時間關聯。由此,當你把cassandra-all作為依賴包包含到你的專案中,cassandra-all宣告將導致log4jslf4j-log4j12同時被新增為依賴包。假使SLF4J在後臺時,你不想用log4J,你可以告訴Maven這倆個檔案,如下文顯示:

<dependencies>
 <dependency>
  <groupId> org.apache.cassandra</groupId>
  <artifactId>cassandra-all</artifactId>
  <version>0.8.1</version>

  <exclusions>
   <exclusion>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
   </exclusion>
   <exclusion>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
   </exclusion>
  </exclusions>

 </dependency>
</dependencies>

注意:SLF4J發出的警告只是警告。甚至多個繫結存在時,SLF4J將選取一個日誌框架/實現,然後與它繫結。SLF4J選取繫結的方式由java虛擬機器決定,應該隨機考慮所有的實際目的。1.6.6版本,SLF4J會以框架/實現類的實際範圍命名。

例如類庫或框架的這些嵌入的元件不能宣告任何SLF4J的繫結,除了依賴slf4j-api。當一個包庫在SLF4J繫結上宣告一個編譯時間依賴,它會欺騙你並且繫結到最後的使用者,這樣就與 SLF4J的目的背道而馳了。當你遇到嵌入元件在SLF4J繫結上宣告編譯時間依賴,請及時聯絡這些作者,友好地請他們修復這些方法。

Slf4j-api版本不匹配繫結

SLF4J繫結標明人工打的jar包,例如用來把slf4j繫結到基本日誌框架的slf4j-jdk14.jar 或 slf4j-log4j12.jar,java.util.logging和個別log4j。

混用不同版本的slf4j-api.jar和SLF4J繫結會導致問題。例如,如果你用slf4j-api-1.7.19.jar,然後你也應該用slf4j-simple-1.7.19.jar,用slf4j-simple-1.5.5.jar將不起作用。

注意: 從客戶端的角度,所有版本的slf4j-api版本都是相容的。在任意N和M版本slf4j-api下,通過slf4j-api-N.jar編譯的客戶端程式碼在slf4j-api-M.jar下也將執行良好。你只需確定繫結版本匹配slf4j.jar。你不需要擔心專案中已給出的依賴庫slf4j-api的版本。你能用任意slf4j-api.jar版本,只要slf4j-api.jar版本和它的繫結匹配,就不會有問題。

在初始化時,如果SLF4J懷疑有任任何api和繫結版本不匹配問題,它將發出被疑似不匹配的警告資訊。

日誌工廠實現不能為空

這個錯誤在LoggerFactory類找不到合適的繫結時會報告。在類路徑下放置slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar logback-classic.jar中的一個包(只能放一個),這會是個有效的改正方法。

在類路徑下檢測log4j-over-slf4j.jar和 slf4j-log4j12.jar包,替代堆溢位錯誤

slf4j-log4j12 模組的目的是把從log4j日誌到SLF4J的呼叫轉移或重定向。Log4j-over-slf4j模組的目的是把從Log4j-over-slf4j日誌到SLF4J的日誌記錄重定向。如果SLF4J屬於slf4j-log4j12.jar和slf4j-log4j-over-slf4.jar,也會在出現在類路徑中,堆溢位錯誤必然會在第一次呼叫SLF4J或log4j日誌時出現。

如下是類似的異常:

Exception in thread "main" java.lang.StackOverflowError
at java.util.Hashtable.containsKey(Hashtable.java:306)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:36)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category.<init>(Category.java:53)
at org.apache.log4j.Logger..<init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.log4j.Category..<init>(Category.java:53)
at org.apache.log4j.Logger..<init>(Logger.java:35)
at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:39)
at org.apache.log4j.LogManager.getLogger(LogManager.java:39)
subsequent lines omitted...

SINCE 1.5.11  SLF4j取代了必然發生的堆溢位錯誤,通過丟擲一個關於問題實際情況的詳情的異常。這比讓使用者去想堆溢位錯誤的原因要好多了。

更多其他關於這個主題的更多背景,檢視Bridging legacy APIs(http://www.slf4j.org/legacy.html)。

在類路徑下檢測jcl-over-slf4j.jar 和 slf4j-jcl.jar包,替代堆溢位錯誤

slf4j-jcl模組的目的是把從SLF4J到JCL(jakarta commons logging)的呼叫轉移或重定向。jcl-over-slf4j模組的目的是從JCL日誌到SLF4J的日誌記錄轉移或重定向。如果SLF4J屬於jcl-over-slf4j.jar和slf4j-jcl.jar,也會在出現在類路徑中,堆溢位錯誤必然會立即在第一次呼叫SLF4J或JCL日誌時出現。

如下是類似的異常:

Exception in thread "main" java.lang.StackOverflowError
at java.lang.String.hashCode(String.java:1482)
at java.util.HashMap.get(HashMap.java:300)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:67)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:289)
at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:69)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:249)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
subsequent lines omitted...

從版本 1.5.11開始  SLF4j取代了必然發生的堆溢位錯誤,通過丟擲一個關於問題實際情況的詳情的異常。這比讓使用者去想堆溢位錯誤的原因要好多了。

載入類” org.slf4j.impl.StaticMDCBinder”失敗

這個錯誤表明在類路徑下沒找到合適的SLF4J繫結。在類路徑下放置slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar logback-classic.jar中的一個包(只能放一個)會解決這個問題。

MDCAdapter不能為空

當org.slf4j.MDC class類沒有被正確地初始化時會報告此錯誤。像上面已列出的項一樣的情況和改正方案。

在初始化階段攔截一定數量(N)的日誌記錄,現在重新顯示。這些遵循底層日誌系統過濾規則

從1.7.版本,在初始化階段產生的日誌記錄被記錄下來,然後在初始化完成後重新顯示。注意重新顯示的日誌記錄遵循底層日誌系統過濾規則。

原則上,應用中重新顯示出現在第一次日誌記錄發生時,這時多執行緒已經啟動。

在底層日誌系統的預設配置階段建立替代日誌器

像logback和log4j這樣的高階可配置日誌系統,它們會在自身初始化過程中建立可呼叫日誌器的元件。檢視典型的事件LOGBACK-127(http://jira.qos.ch/browse/LOGBACK-127),它不可能實現這樣的日誌建立請求。

為了避免這種雞和蛋問題,在這個過程中(初始化),SLF4J建立了替代日誌器。在此階段替代日誌器的記錄被簡單地扔掉了。在初始化完成後,替代日誌器將轉移記錄早合適的日誌器實現,不然將會作用在LogFactory返回的日誌器上。

如果已建立任何替代日誌器,SLF4J將發出一個日誌的列表。這個列表意欲讓你知道在初始化過程中被這些日誌器拋棄的任何日誌記錄。

SLF4J 1.4.0版本,需要1.2.12及以上的版本

在2005.8.29釋出的log4j1.2.12版本增加了跟蹤等級。在2007.5.16的SLF4J API中增加了跟蹤等級。這樣,,啟動SLF4J1.4.0時,繫結給SLF4J的log4j需要log4j1.2.12及其以上的版本。

當然,像在檔案59報告的一樣(http://jira.qos.ch/browse/SLF4J-59),在你某些環境下,這可能會很難升級log4j版本。為了解決這樣的情況,SLF4J的Log4jLOggerAdapter將把跟蹤等級指為除錯級別。

java.lang.NoClassDefFoundError: org/slf4j/event/LoggingEvent

Logback-classic version 1.1.4及其以後的版本需要1.7.15及其以上版本的slf4j-api。

類路徑中的早期slf4j-api.jar,1.1.4及其以後的logback版本返回的試圖內省的日誌例項將導致類似於下面顯示的NoClassDefFoundError。

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/event/LoggingEvent
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2451)
at java.lang.Class.privateGetPublicMethods(Class.java:2571)
at java.lang.Class.getMethods(Class.java:1429)
at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1261)
at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1122)
at java.beans.Introspector.getBeanInfo(Introspector.java:414)
at java.beans.Introspector.getBeanInfo(Introspector.java:161)

在類路徑下放置1.7.15及其以上的slf4j-api.jar包可以解決此問題。

記住這個問題只會出現在1.1.4及其以後的logback版本,其他的繫結,例如slf4j-log4j, slf4j-jdk14 and slf4j-simple是不受影響的。