簡體   English   中英

SLF4jBridgeHandler 未獲取第三方日志記錄,該日志記錄附加到根記錄器但隨后被刪除

[英]3rd party logging not picked up by SLF4jBridgeHandler which is attached to root logger but then removed

我們的應用程序具有使用 JUL 進行日志記錄的 3rd 方代碼。 我們的應用在類路徑中有jul-to-slf4j.jar 我看到SLF4JBridgeHandler.install()方法被調用(多次),無論出於何種原因,spring 根據某些 ApplicationEvents 清理了幾次日志配置。 我在ApplicationStartedEvent上創建了一個事件偵聽器,以再次確保盡可能晚地安裝處理程序。 我通過檢查SLF4JBridgeHandler.isInstalled()方法進行驗證。 然而,第 3 方日志不斷流向標准輸出。 如果我在 IntelliJ 中對第 3 方日志記錄類進行斷點並調用SLF4JBridgeHandler.isInstalled()它返回 false。 如果我然后執行下面的代碼,日志會被 slf4j 拾取,每個人都很高興。

SLF4JBridgeHandler.install();
LogManager.getLogManager().getLogger("com.3rdparty").setUseParentHandlers(false);

為什么 SLF4J 不斷被卸載? 如何保持安裝? 是否在我們安裝 slf4j 之前創建了第 3 方記錄器,然后通過 install() 調用沒有更新?

為什么 SLF4J 不斷被卸載?

最常見的原因是有代碼調用LogManager.reset() 您可以使用安全管理器找到源

如果您使用 logging.properties 文件,那么只需將網橋添加為處理程序。 這種方式重置實際上是安裝橋處理程序。

handlers= java.util.logging.ConsoleHandler, org.slf4j.bridge.SLF4JBridgeHandler

唯一的缺點是橋處理程序必須對系統類加載器可見。 您可以嘗試的一個非常老套的技巧是繼承 SLF4JBridgeHandler 並覆蓋 equals 以返回 false。 LogManager.reset 將無法刪除此處理程序。

Logger.getLogger("").addHandler(new SLF4JBridgeHandler() {
    public boolean equals(Object o) { return false;}
});

是否在我們安裝 slf4j 之前創建了第 3 方記錄器,然后通過 install() 調用沒有更新?

你必須做一些工作才能找到答案。 在調試您的應用程序時,使用 JConsole Mbeans 或系統輸出調試來遍歷記錄器樹。 安全管理器跟蹤是查找負責刪除處理程序的確切堆棧跟蹤的最佳選擇。

可以有兩個根記錄器嗎?

這在標准 LogManager 下是不會發生的。 Tomcat 有一個對上下文類加載器敏感的實現 該 LogManager 可能會根據上下文類加載器返回相同記錄器名稱的不同實例。 無需通過安全管理器就可以刪除處理程序的唯一另一種方法是根記錄器是否被垃圾收集。 您可以嘗試對根記錄器進行強引用,但這確實不需要。 您應該在已知添加處理程序時打印根記錄器的身份哈希碼,並在刪除處理程序后打印根記錄器的身份哈希碼。 如果值不同,則記錄器被垃圾收集。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM