首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何重新执行Log4j“默认初始化过程”?

如何重新执行Log4j“默认初始化过程”?
EN

Stack Overflow用户
提问于 2011-01-14 07:33:09
回答 3查看 8.8K关注 0票数 21

在运行时,我经常创建/修改log4j Logger、Appender、Level、Layout,并不时需要将所有内容重置为默认值。

Log4j system具有定义明确的,在将log4j类加载到内存中时会执行该are。有没有办法稍后在运行时以编程方式重新执行整个过程?

我在log4j文档中找到了几个resetConfiguration()方法,但不确定它们中是否有任何方法可以执行所做的操作:

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

关于重置log4j配置的任何其他建议都非常受欢迎!谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-15 21:31:08

根据doConfigure方法的documentation

从文件中读取配置。未清除现有配置,也未重置。如果需要不同的行为,则在调用resetConfiguration doConfigure之前先调用方法。

因此,我相信调用LogManager.resetConfiguration()并使用与启动时相同的文件调用PropertyConfigurator.configure()将会做您想要的事情。

Hierarchy类中记录了resetConfiguration()方法。

票数 12
EN

Stack Overflow用户

发布于 2012-08-31 18:46:39

这个问题与我今天早些时候回答的skiphoppy's question有关。他在这里添加的赏金问题需要一个比Jan Zyka更棘手的解决方案:

因为缺省初始化是在LogManager的类加载期间只执行一次的硬编码静态块,所以您需要AOP (面向方面编程),更具体地说,AspectJ来拦截静态初始化器。我在my answer中解释了如何跳过skiphoppy的另一个问题。

好了,现在我们可以截获静态初始化并欺骗LogManager告诉我们网址,但是为了重新执行整个代码块,我们需要另一个称为worker object pattern的技巧。以下是示例代码,解释如下:

示例应用程序类:

代码语言:javascript
复制
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**:**的静态初始化

代码语言:javascript
复制
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的一般概念超出了本答案的范围,因此我假设您了解它,或者为了理解它而阅读一些内容。

  • Log4jAspect在advice.
  • Within通知中拦截LogManager的静态初始化,around()调用(即,静态初始化的执行)被打包在由匿名Runnable实例实现的worker对象内。这有效地将调用包装到一个带有run()方法的对象中,该方法可以随意发出。(啊哈,这是我们的把戏!在更动态的语言中,如Scala,您会将其称为包装静态初始化的词法scope.)
  • After,我们将Runnable实例分配给另一个类的公共静态成员,以便可以在通知内的aspect.
  • Still外部访问它,我们通过调用worker对象的run()方法来继续静态初始化。

到目前为止,一切顺利,现在LogManager类已经正确加载和初始化,就像不存在方面一样。但是现在看看Log4jDemo.main

  • 我们初始化记录器并记录一些事件。
  • 我们等待2秒钟(刚好足够检查控制台输出以了解到目前为止发生的情况)。
  • 我们继续并通过再次调用worker对象的run()方法重新发出默认的初始化

如果您使用命令行参数-Dlog4j.debug=true,您将看到如下所示:

代码语言:javascript
复制
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调用暴露给用户的,但事实是这样的,我们需要这个技巧。我确实怀疑在任何给定的情况下是否有必要重新运行完整的默认初始化块,但因为这个问题被问到了,所以我想准确地回答它,而不是通过建议解决方法。享受吧!

票数 7
EN

Stack Overflow用户

发布于 2018-06-04 23:06:12

Jan Zyka的解决方案为我指明了正确的方向,但我使用的是XML配置文件,而不是属性文件。以下是为我工作的代码:

代码语言:javascript
复制
    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“作为日志消息。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4686531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档