以编程方式加载 Log4j2 配置文件

Posted

技术标签:

【中文标题】以编程方式加载 Log4j2 配置文件【英文标题】:Load Log4j2 configuration file programmatically 【发布时间】:2014-01-31 18:12:41 【问题描述】:

我想从我的应用程序中以编程方式加载 Log4j2 XML 配置文件。

试过这个:

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
Configurator.initialize(null, source);

还有这个:

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
ConfigurationFactory factory = (ConfigurationFactory) XMLConfigurationFactory.getInstance().getConfiguration(source);
ConfigurationFactory.setConfigurationFactory(factory);

但还没有任何效果。

【问题讨论】:

在 log4j2 中重新加载配置时引入了所有向后不兼容的更改,因此指定您正在使用的 log4j2 api 和核心版本是有意义的... 【参考方案1】:

对于最新版本的 log4j,以下是加载外部 log4j2.xml 的方法:

String log4jConfigFile = System.getProperty("user.dir") + File.separator + "log4j2.xml";
ConfigurationSource source = new ConfigurationSource(new FileInputStream(log4jConfigFile));
Configurator.initialize(null, source);

【讨论】:

你应该可以简单地使用Configurator.initialize(null, "fileName"); 为什么将 null 传递给 Configurator.initialize() ?【参考方案2】:

如果您只有一个主入口点,此代码 sn-p 可能会为您节省一些麻烦。 set 属性调用必须在创建任何记录器之前触发。这种方法适用于类路径中的文件。

public class TestProcess 
    static 
        System.setProperty("log4j.configurationFile", "log4j-alternate.xml");
    

    private static final Logger log = LoggerFactory.getLogger(TestProcess.class);


【讨论】:

这很好用,我试图在构造函数上设置属性,但是没有用。静态块已解决。 我有 setProperty() 调用,但不在“静态”块中。一旦我将调用保留在静态块中,它就起作用了。谢谢! 更改系统属性不会影响其他记录器的吗?【参考方案3】:

自己找到了答案。有人可能会觉得它很有用。

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
source.setFile(new File(logConfigurationFile));
source.setInputStream(new FileInputStream(logConfigurationFile));
Configurator.initialize(null, source);

【讨论】:

我正在尝试做同样的事情,但即使使用上面的代码也失败了。您的项目中是否有 log4j2 Web 依赖项?我的 log4j2.xml 在类路径之外,我正在尝试将其加载到具有 @PostConstruct 方法的 Spring bean 中。 我的日志 xml 配置文件在类路径之外。 您的应用程序是 Web 应用程序吗?我应该提到我也在使用 slf4j 来抽象 log4j2。 是的,它是一个网络应用程序。我还使用slf4jjcl 日志路由到log4j2 好吧,酷。这个答案是基于 Servlet 2.5 ......无论如何它的工作都很棒!【参考方案4】:

下面为我工作,Log4j2 和 SLF4J 包装器:

解决方案 1:

public class MyClass 

    static 
        try 
            InputStream inputStream = new FileInputStream("C:/path/to/log4j2.xml");
            ConfigurationSource source = new ConfigurationSource(inputStream);
            Configurator.initialize(null, source);
         catch (Exception ex) 
            // Handle here
        
    

    private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class); // LogManager if not using SLF4J

    public void doSomething() 
        LOGGER.info(...)
    


解决方案 2:

static 
    File log4j2File = new File("C:/path/to/log4j2.xml");
    System.setProperty("log4j2.configurationFile", log4j2File.toURI().toString());

需要toURI() 关注File URI Scheme format,否则会抛出MalformedURLException

来源:

Proper format for log4j2.xml RollingFile configuration https://github.com/jprante/elasticsearch-jdbc/issues/562 https://www.codeproject.com/Questions/190269/MalformedURLException-unknown-protocol-c-How-to-ha https://coderanch.com/t/633544/open-source/java-net-MalformedURLException-initialize-log

【讨论】:

如果我的是 .properties 文件怎么办 @silver 为什么将 null 传递给 Configurator.initialize() ?【参考方案5】:

如果您使用的是 Servlet 3.0 Web 应用程序,您可以使用 Log4jServletContextListener 并执行以下操作:

编写一个从Log4jServletContextListener 扩展的自定义LogContextListener,在您的web.xml 中设置它并禁用自动初始化:

<listener>
    <listener-class>com.example.LogContextListener</listener-class>
</listener>
<context-param>
    <param-name>isLog4jAutoInitializationDisabled</param-name>
    <param-value>true</param-value>
</context-param>

在您的自定义LogContextListener 中覆盖contextInitialized 并设置配置位置

public void contextInitialized(ServletContextEvent event)  
    /* Some logic to calculate where the config file is saved. For 
     * example you can read an environment variable.
     */
    String pathToConfigFile = ... + "/log4j2.xml";
    Configurator.initialize(null, pathToConfigFile);
    super.contextInitialized(event);

比直接在web.xml 中配置位置的优势在于 您可以根据一些附加信息计算路径并访问 log4j2.xml,即使它在您的类路径之外。

【讨论】:

我在 log4j 1.2.x 中使用了类似的解决方案,但无法使用 2.14.x。原因是,我的“LogContextListener”是在 log4j2 已经用 WARN StatusLogger No Log4j 2 configuration file found. Using default configuration... 初始化之后创建的@ 我的监听器是 web.xml 中的第一个监听器,但之前触发的 TLD 文件中还有其他监听器。【参考方案6】:

考虑 - https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/config/Configurator.html

Configurator.initialize(null, "classpath:conf/logger.xml");
or
Configurator.initialize(null, "/full_path/conf/logger.xml");

注意,不要同时使用两者。

【讨论】:

为什么将 null 传递给 Configurator.initialize() ? 请检查上面的javadoc链接。 第一个参数是类加载器,但 javadoc 并没有提供更多信息;如果我正确理解了代码,如果 null 它将使用用于加载 log4j2 的类加载器(更准确地说是 Configurator.class.getClassloader())【参考方案7】:
final URL log4j = Resources.getResource("log4j2-test.xml");
LoggerContext.getContext(false)
  .start(new XmlConfiguration(new ConfigurationSource(
    Resources.asByteSource(log4j).openStream(),
    log4j)));

【讨论】:

仅供参考 - 小心使用“log4j2-test.xml”进行测试。如果这是在 log4j2 检查的任何文件夹中,它将在“log4j2.xml”上使用它,并让您认为您对此的覆盖有效,而实际上并没有。我没有尝试过你的代码,但是我之前的代码 sn-p 遇到了这个问题。我在使用“log4j2-test.xml”时认为一切都在运行时被覆盖,结果发现它被覆盖了,因为 log4j2 首先查找“log4j2-test.xml”,然后是“log4j2.xml”logging.apache.org/log4j/2.0/manual/… @TJR 它是否也适用于新的 CompositeConfiguration() 而不是新的 XmlConfiguration()?【参考方案8】:

如果您使用 .properties 文件进行配置:

String propertiesFile = "./test/Configuration/log4j2.properties";  
ConfigurationSource source = new ConfigurationSource(new FileInputStream(propertiesFile), new File(propertiesFile));
Configurator.initialize(null, source);

【讨论】:

以上是关于以编程方式加载 Log4j2 配置文件的主要内容,如果未能解决你的问题,请参考以下文章

log4j2配置

Log4j2配置

如何以编程方式在运行时添加 Log4J2 附加程序?

Log4j2完整XML参考(详细注释说明)

登录Grails:使用Log4j2重新加载外部配置

log4j2配置文件xml详细了解