2017-04-21 144 views
3

我想以編程方式配置我的java.util.logging.Logger。根據Oracle Docs,似乎有可能。以編程方式配置記錄器

但是這個例子說明什麼是錯在這裏:

public static void main(String[] args) { 
    Logger logger = Logger.getLogger("org.acme.project"); 
    logger.setLevel(Level.SEVERE); 
    logger = null; 

    System.gc(); 

    logger = Logger.getLogger("org.acme.project"); 
    logger.warning("You shouldn't see this warning!"); 
    logger.severe("But this error!"); 
} 

如果您運行的代碼,你會看到兩個消息。但是,如果刪除logger = null;System.gc();,則只會看到正確的第二個,這證明垃圾收集器僅刪除配置的記錄器,並將其保留爲Logger.getLogger(String)並創建一個新的(默認)記錄器。爲了「解決」這個問題,我可以在某個地方舉一個特定記錄器的引用,但我認爲這不是一個好主意。

那麼如何以編程方式定義記錄器?

回答

2

爲了「解決」這個問題,我可以在某個地方舉一個特定記錄器的引用,但我認爲這不是一個好主意。

JDK6u18之前的版本中,LogManager對記錄器持有強烈的參考。這個補丁之後,java.util.logging.Logger.getLogger()方法指向讀者向持有很強的借鑑意義:

注:日誌管理可以只保留弱引用到新創建的Logger。重要的是要明白,如果沒有對記錄器的強引用,那麼以前創建的具有給定名稱的記錄器可能會隨時被垃圾收集。特別是,這意味着如果沒有對其他地方名爲「MyLogger」的記錄器的強引用,那麼諸如getLogger(「MyLogger」).log(...)的兩個背靠背調用可能會使用不同的Logger對象,名爲「MyLogger」在節目中。

一個常見的成語是使用:

private static final String CLASS_NAME = Foo.class.getName(); 
private static final Logger logger = Logger.getLogger(CLASS_NAME); 

原因您定義的CLASS_NAME也就是你使用它的日誌追蹤方法或logp方法

而且,工具像FindBugs將檢測到這種丟失的記錄器模式爲:

LG:潛在的丟失記錄器變化,由於弱引用NCE中的OpenJDK(LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)

+0

花了我一秒鐘才明白爲什麼我從未遇到OP的問題。這絕對是你應該使用的成語。 – Qix

0

用於記錄儀#getLogger的Javadoc引用您的問題:

https://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#getLogger%28java.lang.String%29

注:日誌管理可以只保留弱引用到新創建的Logger。重要的是要明白,如果沒有對記錄器的強引用,那麼以前創建的具有給定名稱的記錄器可能會隨時被垃圾收集。特別是,這意味着如果沒有對其他地方名爲「MyLogger」的記錄器的強引用,那麼諸如getLogger(「MyLogger」).log(...)的兩個背靠背調用可能會使用不同的Logger對象,名爲「MyLogger」在節目中。

反過來記錄儀#getLogger調用日誌管理#addLogger及其文檔還鼓勵你抱着一個參考:

https://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html#addLogger%28java.util.logging.Logger%29

應用程序應該保留自己的參考Logger對象,以避免它被垃圾收集。 LogManager只能保留一個弱引用。