简体   繁体   English

自定义ConfigurationFactory结合log4j2中的配置文件

[英]Custom ConfigurationFactory combined with configuration file in log4j2

I'm trying to Initialize Log4j by Combining Configuration File with Programmatic Configuration .我正在尝试通过将配置文件与编程配置相结合初始化 Log4j

I followed the manual (though it's syntax isn't quite right and it's outdated), which resulted in the following classes:我遵循了手册(尽管它的语法不太正确并且已经过时),这导致了以下类:

CustomConfigurationFactory.java:自定义配置工厂.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:自定义配置.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);

        }

    }
}

Now, when running this and calling ConfigurationFactory.setConfigurationFactory(new CustomConfigurationFactory()) before any calls to the Logging API, I'm getting output to the console in the form of现在,在对 Logging API 进行任何调用之前运行它并调用ConfigurationFactory.setConfigurationFactory(new CustomConfigurationFactory()) ,我将输出到控制台的形式为

ERROR StatusLogger Reconfiguration failed: No configuration found for 'someNumbersAndChars' at 'null' in 'null'

While debugging this, I found out that this is printed the first time I'm acquiring a Logger .在调试时,我发现这是我第一次获取Logger时打印的。 The reason for that is that, if a custom ConfigurationFactory is supplied, the implementation of ConfigurationFactory.getConfiguration(LoggerContext, String, URI) by ConfigurationFactory 's private subclass Factory (which is the default factory) will be overridden by ConfigurationFactory 's implementation.原因是,如果提供自定义ConfigurationFactory ,则ConfigurationFactory的私有子类Factory (默认工厂)的ConfigurationFactory.getConfiguration(LoggerContext, String, URI)实现将被ConfigurationFactory的实现覆盖。

And ConfigurationFactory 's implementation simply returns null if the URI is so, while ConfigurationFactory.Factory 's implementation nevertheless returns a valid configuration.如果 URI 是这样, ConfigurationFactory的实现只会返回null ,而ConfigurationFactory.Factory的实现仍然返回一个有效的配置。

(link to source) (链接到源)

My first idea now would be to override these overloads of ConfigurationFactory.getConfiguration() in my custom factory, but there has to be another way, right?我现在的第一个想法是在我的自定义工厂中覆盖ConfigurationFactory.getConfiguration()这些重载,但必须有另一种方法,对吗? ;) ;)

I solved this problem by calling我通过调用解决了这个问题

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

As an alternative use this JVM start parameter:作为替代使用此 JVM 启动参数:
-Dlog4j.configurationFactory=factory.CustomConfigurationFactory

instead of而不是

ConfigurationFactory.setConfigurationFactory(new CustomConfigurationFactory());

before accessing the LogManager for the first time.在第一次访问LogManager之前。

- ——

EDIT: You can also configure this setting in the file log4j2.component.properties .编辑:您还可以在文件log4j2.component.properties配置此设置。

Content:内容:

log4j.configurationFactory=factory.CustomConfigurationFactory

By doing so you can be sure this setting is applied before any logger classes are loaded and avoid the potential problems of class initialization order.通过这样做,您可以确保在加载任何记录器类之前应用此设置,并避免类初始化顺序的潜在问题。

If you look for usage of org.apache.logging.log4j.util.PropertiesUtil in the Log4j2 sources you can find all settings that can be configured that way.如果您在 Log4j2 源中查找org.apache.logging.log4j.util.PropertiesUtil用法,您可以找到所有可以通过这种方式配置的设置。

- ——

While analyzing / debugging the problem i noticed that my ConfigurationFactory was created, but not used to get the config.在分析/调试问题时,我注意到我的ConfigurationFactory已创建,但未用于获取配置。

Finally i found this passage in the docs , which explains it all (we probably did not call setConfigurationFactory early enough):最后我在 文档中找到了这一段,它解释了这一切(我们可能没有足够早地调用setConfigurationFactory ):

During initialization, Log4j 2 will search for available ConfigurationFactories and then select the one to use.在初始化期间,Log4j 2 会搜索可用的 ConfigurationFactories,然后选择要使用的。 The selected ConfigurationFactory creates the Configuration that Log4j will use.选定的 ConfigurationFactory 创建 Log4j 将使用的 Configuration。 Here is how Log4j finds the available ConfigurationFactories:以下是 Log4j 如何找到可用的 ConfigurationFactories:

  1. A system property named "log4j.configurationFactory" can be set with the name of the ConfigurationFactory to be used.可以使用要使用的 ConfigurationFactory 的名称设置名为“log4j.configurationFactory”的系统属性。
  2. ConfigurationFactory.setConfigurationFactory(ConfigurationFactory) can be called with the instance of the ConfigurationFactory to be used. ConfigurationFactory.setConfigurationFactory(ConfigurationFactory) 可以使用要使用的 ConfigurationFactory 的实例调用。 This must be called before any other calls to Log4j.这必须在对 Log4j 的任何其他调用之前调用。
  3. A ConfigurationFactory implementation can be added to the classpath and configured as a plugin in the "ConfigurationFactory" category.可以将 ConfigurationFactory 实现添加到类路径并配置为“ConfigurationFactory”类别中的插件。 The Order annotation can be used to specify the relative priority when multiple applicable ConfigurationFactories are found.当找到多个适用的 ConfigurationFactories 时,Order 注释可用于指定相对优先级。

I think this may be due to the @Order() you have.我认为这可能是由于您拥有的@Order() I couldn't find any documentation that explained how the specified orders are compared, but my belief is that higher numbers are used by preferrence.我找不到任何解释如何比较指定订单的文档,但我相信更高的数字是由偏好使用的。 The default XmlConfigurationFactory has an order of 5 ( log4j version 2.13.1 ) so if you change your order to be 6 you should get your factory as you require.默认的XmlConfigurationFactory的订单为 5( log4j版本2.13.1 ),因此如果您将订单更改为 6,您应该根据需要获取工厂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM