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

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

如果您愿意使用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, ..)则将在静态块内的某一点调用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的情况下明确拦截日志调用。 我只是想提一下。

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

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

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

即使这样,在默认配置过程之后可能还有其他编程配置(例如Spring Log4jConfigListener ) – 不一定有单个配置URL。

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

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

设置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); } } 

将其插入到java调用中:

 -Dlog4j.configDebug=true 

就这样。