【问题标题】:Custom ConfigurationFactory combined with configuration file in log4j2自定义 ConfigurationFactory 与 log4j2 中的配置文件相结合
【发布时间】:2017-10-28 21:26:14
【问题描述】:

我正在尝试Initialize Log4j by Combining Configuration File with Programmatic Configuration

我遵循了手册(虽然它的语法不太正确并且已经过时),结果产生了以下类:

CustomConfigurationFactory.java:

package factory;

import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.plugins.Plugin;

import java.net.URI;

@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(1)
public class CustomConfigurationFactory extends ConfigurationFactory {

    /**
     * Valid file extensions for XML files.
     */
    private static final String[] SUFFIXES = new String[]{".xml", "*"};

    /**
     * Return the Configuration.
     *
     * @param source The InputSource.
     * @return The Configuration.
     */
    public Configuration getConfiguration(LoggerContext context, ConfigurationSource source) {

        return new CustomConfiguration(context, source);

    }

    /**
     * Returns the file suffixes for XML files.
     * @return An array of File extensions.
     */
    public String[] getSupportedTypes() {

        return SUFFIXES;

    }

}

CustomConfiguration.java:

package factory;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfiguration;

import java.util.Map;

public class CustomConfiguration extends XmlConfiguration {

    CustomConfiguration(LoggerContext context, ConfigurationSource configSource) {

        super(context, configSource);

    }

    @Override
    protected void doConfigure() {

        super.doConfigure();

        final LoggerConfig rootLogger = getRootLogger();

        final Map<String, Appender> appenderMap = rootLogger.getAppenders();

        if (MainClass.DEBUG) {

            rootLogger.addAppender(appenderMap.get("Console"), Level.ALL, null);

        } else {

            rootLogger.addAppender(appenderMap.get("Mail"), Level.ERROR, null);

        }

    }
}

现在,当运行此程序并在对 Logging API 进行任何调用之前调用 ConfigurationFactory.setConfigurationFactory(new CustomConfigurationFactory()) 时,我会以

的形式将输出输出到控制台
ERROR StatusLogger Reconfiguration failed: No configuration found for 'someNumbersAndChars' at 'null' in 'null'

在调试时,我发现这是在我第一次获取Logger 时打印的。原因是,如果提供了自定义 ConfigurationFactoryConfigurationFactory 的私有子类 Factory(这是默认工厂)对 ConfigurationFactory.getConfiguration(LoggerContext, String, URI) 的实现将被 ConfigurationFactory 的实现覆盖.

如果 URI 是这样,ConfigurationFactory 的实现只返回 null,而 ConfigurationFactory.Factory 的实现仍然返回一个有效的配置。

(link to source)

我现在的第一个想法是在我的自定义工厂中覆盖 ConfigurationFactory.getConfiguration() 的这些重载,但必须有另一种方法,对吧? ;)

【问题讨论】:

    标签: java debugging logging log4j2


    【解决方案1】:

    我通过调用解决了这个问题

    System.setProperty("log4j.configurationFactory", CustomConfigurationFactory.class.getName());
    

    也可以使用这个 JVM 启动参数:
    -Dlog4j.configurationFactory=factory.CustomConfigurationFactory

    而不是

    ConfigurationFactory.setConfigurationFactory(new CustomConfigurationFactory());
    

    在第一次访问LogManager之前。

    -

    编辑:您还可以在文件log4j2.component.properties 中配置此设置。

    内容:

    log4j.configurationFactory=factory.CustomConfigurationFactory
    

    通过这样做,您可以确保在加载任何记录器类之前应用此设置,并避免类初始化顺序的潜在问题。

    如果您在 Log4j2 源中查找 org.apache.logging.log4j.util.PropertiesUtil 的用法,您可以找到所有可以通过这种方式配置的设置。

    -

    在分析/调试问题时,我注意到我的 ConfigurationFactory 已创建,但未用于获取配置。

    最后我在docs 中找到了这段话,它解释了一切(我们可能没有足够早地调用setConfigurationFactory):

    在初始化期间,Log4j 2 将搜索可用的 ConfigurationFactories,然后选择要使用的。选定的 ConfigurationFactory 创建 Log4j 将使用的配置。以下是 Log4j 如何找到可用的 ConfigurationFactories:

    1. 可以使用要使用的 ConfigurationFactory 的名称设置名为“log4j.configurationFactory”的系统属性。
    2. ConfigurationFactory.setConfigurationFactory(ConfigurationFactory) 可以与要使用的 ConfigurationFactory 的实例一起调用。 这必须在对 Log4j 的任何其他调用之前调用。
    3. 可以将 ConfigurationFactory 实现添加到类路径并配置为“ConfigurationFactory”类别中的插件。当找到多个适用的 ConfigurationFactories 时,Order 注释可用于指定相对优先级。

    【讨论】:

    • 这个答案在某种程度上帮助了我的问题,但在查看文档后我的理解有点不同。由于根据问题,我打算使用配置文件和我自己的配置工厂,我认为 Log4j2 可以根据注释自动加载自定义配置工厂。
    • 感谢您的详尽回答。这也帮助我找到了我的问题,并给了我一些其他尝试的途径。但是,正如您在上面所说的,我没有足够早地设置自定义记录器。我完全忽略了一个 Logger,我在 Main 类中分配了内联初始化。在移动初始化之后,一切都像一个魅力。对于遇到ConfigurationFactory 问题的其他人,请务必在设置ConfigurationFactory 之前仔细检查您没有初始化Logger 实例!
    • 你看,这让我很困惑。我最后没有使用这些步骤来包含 ConfigurationFactory 并且由于某种原因它仍然有效。对 ConfigurationFactory 进行更改会导致日志记录发生更改。出于某种原因,log4j2 似乎无论如何都能找到配置工厂。任何想法这是如何工作的?使用 log4j 2.9.0。
    • 您是否在 ConfigurationFactory 上使用 @Order 注解?我相信 log4j 会扫描所有类以查找特定注释并自动添加这些类。
    【解决方案2】:

    我认为这可能是由于您拥有的@Order()。我找不到任何解释如何比较指定订单的文档,但我认为优先使用更高的数字。默认XmlConfigurationFactory 的顺序为 5(log4j 版本 2.13.1),因此如果您将顺序更改为 6,您应该得到您需要的工厂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      • 1970-01-01
      • 2016-07-03
      • 1970-01-01
      • 2015-02-15
      • 2015-10-10
      • 2016-05-27
      相关资源
      最近更新 更多