4

Log4j 默认初始化通过一个过程来查找和使用 URL 进行配置。之后,您如何找出最终使用的 URL,而不必自己编写相同的程序?(如果您必须自己编写代码,您可能无法得到与 log4j 完全相同的代码,而且它可能会在未来的版本中发生变化。)

4

4 回答 4

4

使用的过程被硬编码在 中的静态初始化程序块中LogManager,因此似乎没有办法挂钩它。它告诉你发生了什么的唯一地方是

LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");

LogLog它本身是硬编码的,可System.out.println用于这些消息,所以我能看到的唯一可能性是打开调试(-Dlog4j.debug=true)并System.setOut在 log4j 初始化之前以某种方式连接,然后解析调试日志消息。但这可能比自己编写配置过程更脆弱。

即便如此,在默认配置过程(例如 Spring )之后可能已经应用了其他编程配置Log4jConfigListener- 不一定有单个配置 URL。

将 log4j 功能请求放入一个可以从其他地方调用的静态方法中分解配置文件搜索代码可能是值得的,但是当您可能不得不处理较早版本的 log4j 时,这将无济于事。

于 2012-08-30T16:04:06.767 回答
4

如果你愿意使用 AspectJ LTW (load-time weaving),你可以看看LogManagerIan Roberts 提到的静态初始化。在log4j 1.2.14中,它看起来像这样:

static {
    // (...)
    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if (override == null || "false".equalsIgnoreCase(override)) {
        // (...)
        URL url = null;

        // (...)    
        // If we have a non-null url, then delegate the rest of the
        // configuration to the OptionConverter.selectAndConfigure method.
        if (url != null) {
            LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
            OptionConverter.selectAndConfigure(
                url, configuratorClassName, LogManager.getLoggerRepository()
            );
        } else {
            LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
        }
    }
}

显然,如果可以确定默认 URL,OptionConverter.selectAndConfigure(URL, ..)则将在静态块内的某一点调用,以便使用该 URL初始化log4j 。

通过AspectJ,捕获该方法调用非常简单:

import java.net.URL;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.LogManager;

public aspect Log4jAspect {
    before(URL defaultURL) :
        within(LogManager) &&
        cflow(staticinitialization(LogManager)) &&
        call(* OptionConverter.selectAndConfigure(URL, ..)) &&
        args(defaultURL, ..)
    {
        System.out.println("log4j default URL = " + defaultURL);
    }
}

在散文中,这段代码意味着:

  • 如果我们在 LogManager 类中并且
  • 在静态类初始化的控制流程中和
  • OptionConverter.selectAndConfigure叫做,
  • 然后捕获第一个参数(URL)和
  • 将其打印到控制台(您也可以执行其他操作)。

如果没有默认 URL,则不会打印任何内容。您可以将其分配给任何类的静态成员或您喜欢的任何东西,而不是打印 URL。

这是您的问题的解决方案,我对其进行了测试,并且可以正常工作。我很乐意收到回答您问题的赏金,即使该解决方案可能使用了您没有想到的技术。但它解决了问题。:-)


编辑:在没有找到默认 URL 的情况下,也可以显式拦截日志调用,即使我认为没有必要。我只是想提一下。

于 2012-08-30T23:01:02.803 回答
4

如果您可以设置自己的配置器,则可以执行以下操作:

设置 JAVA 系统属性: -Dlog4j.configuratorClass=MyConfigurator 然后让您的配置器实例拦截 doConfigure 调用。

public class MyConfigurator implements Configurator
{
    public static URL url;

    @Override
    public void doConfigure(URL url, LoggerRepository repository)
    {
        this.url = url;
        new PropertyConfigurator().doConfigure(url, repository);
    }
}
于 2012-09-03T04:33:51.130 回答
1

将此插入您的 java 调用中:

-Dlog4j.configDebug=true

就这样。

于 2012-08-31T11:47:23.070 回答