using log4j2 configuration builder to initialize logger after startup

▼魔方 西西 提交于 2019-12-11 05:14:59

问题


I created a custom log4j configuration using ConfigurationBuilder and want to initialize this configuration and start using log4j afterwards, in otherwards without having a configuration file when the project initializes...

according to this page under Reconfigure Log4j Using ConfigurationBuilder with the Configurator, it says -

An alternative to a custom ConfigurationFactory is to configure with the Configurator. Once a Configuration object has been constructed, it can be passed to one of the Configurator.initialize methods to set up the Log4j configuration. Using the Configurator in this manner allows the application control over when Log4j is initialized. However, should any logging be attempted before Configurator.initialize() is called then the default configuration will be used for those log events.

So this should be possible.

This is my code - its almost exactly as it is on that page with a few adjustments -

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

        builder.setStatusLevel(DEBUG);
        builder.setConfigurationName("RollingBuilder");
        //create a console appender
        AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
        appenderBuilder.add(builder.newLayout("PatternLayout"))
                .addAttribute("pattern", "%d{dd/MMM/yyyy HH:mm:ss,SSS}- %c{1}: %m%n");
        builder.add(appenderBuilder);
        //create a rolling file appender
        LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d [%t] %-5level: %msg%n");
        ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
                .addComponent(builder.newComponent("TimeBasedTriggeringPolicy")
                        .addAttribute("interval", "1")
                        .addAttribute("modulate", "true"));
        ComponentBuilder rolloverStrategy = builder.newComponent("DefaultRolloverStrategy")
                .addAttribute("max", "4");
        appenderBuilder = builder.newAppender("RollingFile", "RollingFile")
                .addAttribute("fileName", "logs/app-info.log")
                .addAttribute("filePattern", "logs/app-info-%d{yyyy-MM-dd}--%i.log")
                .add(layoutBuilder)
                .addComponent(triggeringPolicy)
                .addComponent(rolloverStrategy);
        builder.add(appenderBuilder);
        //create a new logger
        builder.add(builder.newLogger("root", Level.DEBUG)
                .add(builder.newAppenderRef("RollingFile"))
                .addAttribute("additivity", false));

        builder.add(builder.newRootLogger(Level.DEBUG)
                .add(builder.newAppenderRef("RollingFile")));
        LoggerContext ctx = Configurator.initialize(builder.build());

However, when I call that code, then do log statements right after, I get the error -

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'org.apache.logging.log4j.simplelog.StatusLogger.level' to TRACE to show Log4j2 internal initialization logging.

So obviously it thinks I dont have a configuration file... does anyone know how I can get my Logger to recognize this configuration file I created in code?


回答1:


from Log4j 2 docs

Here is how Log4j finds the available ConfigurationFactories:

  1. A system property named "log4j.configurationFactory" can be set with the name of the ConfigurationFactory to be used.
  2. ConfigurationFactory.setConfigurationFactory(ConfigurationFactory) can be called with the instance of the ConfigurationFactory to be used. This must be called before any other calls to Log4j.
  3. A ConfigurationFactory implementation can be added to the classpath and configured as a plugin in the "ConfigurationFactory" category. The Order annotation can be used to specify the relative priority when multiple applicable ConfigurationFactories are found.

In a test I've arranged this:

public class Log4j2Example {

    static {
        System.setProperty("log4j.configurationFactory", CustomConfigurationFactory.class.getName());
    }
    private static final Logger LOG = LogManager.getLogger(Log4j2Example.class);

    public static void main(String[] args) {
        LOG.debug("This Will Be Printed On Debug");
        LOG.info("This Will Be Printed On Info");
        LOG.warn("This Will Be Printed On Warn");
        LOG.error("This Will Be Printed On Error");
        LOG.fatal("This Will Be Printed On Fatal");
        LOG.info("Appending string: {}.", "Hello, World");
    }
}

The ConfigurationFactory implemented:

@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomConfigurationFactory extends ConfigurationFactory {
---8<----

}

If you set the value of log4j.configurationFactory property before log4j2 start, it's done.




回答2:


If you prefer using the Configurator instead of using a custom ConfigurationFactory, you have to make sure that your initialization is applied before any call to LogManager.getLogger(...). For instance, you could use a static initialization block

public class MyApplication {

  public static final Logger log;

  static {
    createCustomConfiguration();
    log = LogManager.getLogger(MyApplication.class);
  }

  public static void createCustomConfiguration() {
    // your initialization code
  }

  public static void main(String[] args) {
    log.info("Log and roll!");

    // do stuff
  }
}


来源:https://stackoverflow.com/questions/44553699/using-log4j2-configuration-builder-to-initialize-logger-after-startup

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!