如何在log4j默认初始化中找到使用的URL?

时间:2012-08-28 15:16:56

标签: java logging log4j

Log4j default initialization通过一个程序来查找和使用URL进行配置。之后,如何找出最终使用的URL,而无需自己编写相同的程序? (如果你必须自己编写代码,你可能不会像log4j那样完全相同,而且在将来的版本中也可能会改变它。)

4 个答案:

答案 0 :(得分:4)

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

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

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

即使这样,在默认配置过程(例如Spring System.setOut)之后可能已经应用了其他编程配置 - 不一定有单个配置URL。

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

答案 1 :(得分:4)

如果您愿意使用AspectJ LTW(加载时编织),您可以查看Ian Roberts提到的LogManager的静态初始化。在 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。

这是您的问题的解决方案,我测试了它,它的工作原理。我很乐意收到回答您问题的赏金,即使该解决方案可能使用了您没有想到的技术。但它解决了这个问题。 : - )


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

答案 2 :(得分: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);
    }
}

答案 3 :(得分:1)

将此插入您的java调用:

-Dlog4j.configDebug=true

多数人。