如何在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
就这样。