How to configure Log4J programmatically in two steps?

Java Conceptuel Diagram

How to configure Log4J programmatically in two steps?

About

This article shows you how to configure Log4j 2.2 programmatically by extending the actual configuration.

Why extend the actual configuration?

Because Log4J gives the possibility to reload a configuration file. If this were the case, the programmatic configuration would be lost.

Steps

Steps 1: Programmatic Configuration

In this step, we create a configuration that extends an Xml Configuration (ie Log4j.xml)

  • We add a logger called TEST_LOGGER
  • that gets two programmatically created Appenders:
    • a file Appender
    • a console Appender
public class Log4JConfiguration extends XmlConfiguration {


  public static final String TEST_LOGGER = Log4JConfiguration.class.getName();

  public Log4JConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
    super(loggerContext, source);
  }

  @Override
  protected void doConfigure() {
  
    super.doConfigure();


    PatternLayout defaultLayout = PatternLayout.createDefaultLayout();
    FileAppender fileAppender = FileAppender.newBuilder()
      .setName("TestLogFile")
      .setConfiguration(this)
      .withFileName("test.log")
      .setLayout(defaultLayout)
      .setImmediateFlush(true)
      .build();
    this.addAppender(fileAppender);
    
    ConsoleAppender console = ConsoleAppender.newBuilder()
      .setName("TestConsole") // mandatory
      .setConfiguration(this)
      .setTarget(ConsoleAppender.Target.SYSTEM_OUT)
      .build();
    testLogger.addAppender(console, null, null);
    
    LoggerConfig testLogger = LoggerConfig.newBuilder()
      .withLoggerName(TEST_LOGGER)
      .withAdditivity(false)
      .withConfig(this)
      .withLevel(Level.INFO)
      .build();
    
    // Add the appenders to the logger
    testLogger.addAppender(fileAppender, null, null);
    testLogger.addAppender(myFileAppender,null, null);
    
    // Add the logger to the configuration
    addLogger(testLogger.getName(), testLogger);

  }

}

Step 2: Advertise it with a ConfigurationFactory

The below code is a factory that:

  • is registered via the @Plugin
  • return the previous Log4JConfiguration

When a Log4j logger is asked for the first time, it invokes this factory and build the configuration.

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

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

  /**
   * Return the Configuration.
   *
   * @param source The InputSource.
   * @return The Configuration.
   */
  @Override
  public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
    return new Log4JConfiguration(loggerContext, source);
  }

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


}

Annexes

Remark on Appenders

Note that Appenders created with the builder factory (and not with the Node class representing the file loaded) does not support out-of-the-box lookups to uses variables from the context.

You may then: * add them in your original configuration and * also create a new log4j configuration with new Appenders (See below)

How to load another log4j configuration

You can do it:

LoggerContext loggerContext = this.getLoggerContext();

// Get your configuration as string
String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration>....</Configuration>"; 
InputStream stream = new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
ConfigurationSource configurationSource = new ConfigurationSource(stream);

Configuration currentReadConfiguration = ConfigurationFactory.getInstance().getConfiguration(loggerContext, configurationSource);
currentReadConfiguration.initialize();

// then you can access the appenders
Appender appender = currentReadConfiguration.getAppender("myAppenderName");







Share this page:
Follow us:
Task Runner