簡體   English   中英

如何重新執行Log4j“默認初始化過程”?

[英]How to Re-Execute Log4j “Default Initialization Procedure”?

在運行時,我經常創建/修改log4j Loggers,Appenders,Levels,Layouts以及需要將所有內容重置為默認值的時間。

Log4j系統具有明確定義的默認初始化過程 ,該過程在將log4j類加載到內存時執行。 有沒有辦法在以后的運行時以編程方式重新執行整個過程?

我在log4j文檔中找到了幾個resetConfiguration()方法,但不確定它們中的任何一個是否會執行默認初始化過程

  • BasicConfigurator.resetConfiguration();
  • Hierarchy.resetConfiguration();
  • LogManager.resetConfiguration();

關於重置log4j配置的任何其他建議都是受歡迎的! 謝謝。

根據doConfigure方法的文檔

從文件中讀取配置。 現有配置不會被清除也不會被重置 如果你需要一個不同的行為,然后調用resetConfiguration調用doConfigure前法

因此我相信調用LogManager.resetConfiguration()並使用與啟動時相同的文件調用PropertyConfigurator.configure()將執行您想要的操作。

Hierarchy類中記錄了resetConfiguration()方法。

這個問題與我今天早些時候回答的skiphoppy問題有關。 他在這里添加的賞金問題需要一個比Jan Zyka更棘手的解決方案:

因為默認初始化是在LogManager類加載期間僅執行一次的硬編碼靜態塊,所以需要AOP(面向方面​​編程),更具體地說是AspectJ以攔截靜態初始化器。 我在回答 skiphoppy的另一個問題時解釋了如何做到這一點。

好的,現在我們可以攔截靜態初始化並誘騙LogManager告訴我們URL,但是為了重新執行整個代碼塊,我們需要另一種稱為工作對象模式的技巧。 以下是示例代碼,說明如下:

示例應用程序類:

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class Log4jDemo {
    public static Runnable log4jDefaultInitCmd;

    private static Logger logger = Logger.getLogger("scrum-master.de");

    public static void main(String[] args) throws InterruptedException {
        BasicConfigurator.configure();
        logger.info("Hello world!");
        logger.info("Now sleeping for 2 sec...");
        Thread.sleep(2000);
        logger.info("I am awake again!");
        if (log4jDefaultInitCmd != null) {
            logger.info("Re-running log4j default initialisation");
            log4jDefaultInitCmd.run();
        }
        logger.info("Done");
    }
}

Aspect攔截LogManager靜態初始化:

import org.apache.log4j.LogManager;

public aspect Log4jAspect {
    Object around() : staticinitialization(LogManager) {
        System.out.println("log4j static initialisation");
        Log4jDemo.log4jDefaultInitCmd = new Runnable() {
            @Override public void run() {
                proceed();
            }
        };
        Log4jDemo.log4jDefaultInitCmd.run();
        return null;
    }
}

這個怎么運作:

解釋AOP的一般概念超出了這個答案的范圍,所以我假設你知道它或者要讀一些東西以便理解它。

  • Log4jAspectaround()建議中攔截LogManager的靜態初始化。
  • 在通知中, proceed()調用(即靜態初始化的執行)被打包在由匿名Runnable實例實現的worker對象中。 這有效地使用run()方法將調用包裝到一個對象中,該方法可以隨意發出。 (啊哈,這是我們的伎倆!在像Scala這樣的更動態的語言中,你會稱之為詞法范圍。)
  • 在包裝靜態初始化之后,我們將Runnable實例分配給另一個類的公共靜態成員,以便在方面之外可以訪問它。
  • 仍然在建議中,我們通過調用worker對象的run()方法繼續靜態初始化。

到目前為止,非常好,現在LogManager類已經被正確加載和初始化,就好像沒有方面確實存在一樣。 但現在看看Log4jDemo.main

  • 我們初始化記錄器並記錄一些事件。
  • 我們等待2秒鍾(足夠的時間來檢查控制台輸出到目前為止發生了什么)。
  • 我們通過再次調用worker對象的run()方法繼續並重新發出默認初始化

如果使用命令行參數-Dlog4j.debug=true ,您將看到如下內容:

log4j static initialisation
log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@17182c1.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@17182c1 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@17182c1.
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
12:41:22,647  INFO de:13 - Hello world!
0 [main] INFO scrum-master.de  - Hello world!
12:41:22,663  INFO de:14 - Now sleeping for 2 sec...
16 [main] INFO scrum-master.de  - Now sleeping for 2 sec...
12:41:24,663  INFO de:16 - I am awake again!
2016 [main] INFO scrum-master.de  - I am awake again!
12:41:24,663  INFO de:18 - Re-running log4j default initialisation
2016 [main] INFO scrum-master.de  - Re-running log4j default initialisation
log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@17182c1.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@17182c1 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@17182c1.
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
12:41:24,663  INFO de:21 - Done
2016 [main] INFO scrum-master.de  - Done

Tadaa! 如您所見,默認初始化確實已執行兩次。 日志輸出證明了這一點。 例如,您在日志中看到兩次Using URL [file:/(...)]

結論:

雖然這不是一個特別好的方法來重新發布log4j默認初始化,而不是更加可取的情況,它不是硬編碼但是通過API調用暴露給用戶,事實就是這樣,我們需要這個技巧。 我懷疑在任何給定的情況下都應該重新運行完整的默認初始化塊,但是因為問了這個問題,我想准確地回答它,而不是建議一個解決方法。 請享用!

Jan Zyka的解決方案指出了我正確的方向,但我使用的是XML配置文件而不是屬性文件。 這是適合我的代碼:

    LogManager.resetConfiguration(); // clear any existing config first
    LoggerRepository loggerRepository = LogManager.getLoggerRepository();
    DOMConfigurator domConfigurator = new DOMConfigurator();
    try (
        InputStream is = MyClassName.class.getResourceAsStream("/log4j.xml");
    ) {
        domConfigurator.doConfigure(is, loggerRepository);
    }
    LOGGER.info("abc123");

我得到一個格式正確的log4j日志條目,其中“abc123”作為日志消息。

暫無
暫無

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

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