【问题标题】:Better way to initialize log4j2 (TWO) programmatically以编程方式初始化 log4j2 (TWO) 的更好方法
【发布时间】:2015-02-14 22:20:03
【问题描述】:

这是我加载 log4j2.xml 文件所做的工作,从另一个属性文件中指定日志文件位置,以保持配置简单,以达到支持目的:

MyProperties props = MyProperties.getInstance();
System.setProperty(MyConstants.AUDIT_LOG_ENV_VAR,
        props.getAuditLogFileName());
ConfigurationSource source =
        new ConfigurationSource(new FileInputStream(new File(
                System.getProperty(MyConstants.PROPERTIES_FILE_ENV_VAR)
                    + "/log4j2.xml")));
Configurator.initialize(null, source);

并且 log4j2 将获取并使用我的文件名,因为我已经在 Appender 中使用 envvar 替换指定了它:

<File name="AuditLogger" fileName="${sys:AUDIT_LOG}">
  <PatternLayout pattern="DATETIME  %d{yyyy-MM-dd HH:mm:ss:SSS zzz}%n%msg%n" />
</File>

但是我不喜欢它,因为在下一行代码再次读回之前将文件名值推送到系统环境有一种味道。

我喜欢Configure log4j2 programmatically using ConfigurationFactory,但似乎没有类似的方法可以在 log4j2.xml 文件之上构建更多内容 - 或者有吗?

【问题讨论】:

  • 你不使用 Java 7+ 吗?
  • 我没有听从你的意图。如果您不想以编程方式设置属性,是否将其设置为 jvm 参数?
  • @AndyDufresne 你到底在问什么?我将很难更明确地表达我的问题。最后两段是关键。

标签: java logging configuration log4j2


【解决方案1】:

一般log4j2团队不推荐程序化配置:api和core jar的分离是为了给开发者一个API和实现的清晰分离。编程配置依赖于实现细节,因此可能会在未来的版本中中断。

如果有任何无法通过配置完成的事情,请告诉我们,以便我们改进。

对于您的特定用例:您似乎想将系统属性设置为某个值之前 log4j2 根据该值初始化自身。如果这是一个独立的应用程序,避免依赖 log4j2 实现细节的一种方法是在引用任何 log4j2 类之前设置所有必要的系统属性:

public class MainWrapper {
    public static void main(String[] args) {
        System.setProperty("key", "value");
        // ... 
        ActualMain.main(args); // delegate to the actual start of the application
    }
}

我想提请您注意的另一种方法是创建您自己的自定义查找。这可以在几行代码中使用 log4j2 plugin 完成。这也依赖于一些实现细节,但结果更加强大和可重用。

package com.mycompany;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.AbstractLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;

/** Looks up keys in MyProperties singleton. */
@Plugin(name = "MyProperties", category = StrLookup.CATEGORY)
public class MyPropertiesLookup extends AbstractLookup {
    @Override public String lookup(final LogEvent event, final String key) {
        return MyProperties.getInstance().getValue(key);
    }
}

然后,在您的配置中,您可以使用自定义查找而不是系统属性:

<File name="AuditLogger" fileName="${MyProperties:AUDIT_LOG}">
  <PatternLayout pattern="DATETIME  %d{yyyy-MM-dd HH:mm:ss:SSS zzz}%n%msg%n" />
</File>

【讨论】:

  • 感谢关于插件的精彩回答 - 但这只是其中的一半。我还使用MyProperties 来获取不在类路径上的 log4j2.xml 位置。你建议不要使用 log4j2 实现——你会怎么做?
  • 我会用这个系统属性指定配置文件的完整路径:-Dlog4j.configurationFile=path/to/log4j2.xml
  • 我想你可能会这么说。但后来我又回到了与之前相同的情况——将一个变量推到环境中,以便稍后再读回一行代码。这次是 log4j2.xml 文件位置,而不是 appender 的日志文件。是否有插件技术告诉 log4j2 在哪里获取 log4j2.xml?
  • 对不起,我不清楚。 Log4j 知道此系统属性,如果您指定此属性,它将找到配置文件。然后就不需要再读回来了:log4j 会自动进行配置/初始化。 (因此您不再需要问题中的自定义代码。)另请参阅常见问题解答:logging.apache.org/log4j/2.x/faq.html#config_location
  • 是的,我明白了——我的意思是,在从MyProperties 获取值之后,我必须在代码中设置log4j.configurationFile,然后 log4j 在下一行读回它(大约.)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 2014-08-20
相关资源
最近更新 更多