2

Today I have a problem to reconfigure the log4j2 configuration correctly. To explain the problem I created a sample application that matches nearly our productive code. The sample project structure is shown in the following picture:

enter image description here

For developer purpose we want to start the main application with a wrapper class to configure some parameter like logging configuration or system properties which should not be placed in the productive code. Therefore the productive log4j2 configuration should be replaced by the developer one to set the log level more specific and avoid a file appending of the log entries. Following is the code for the productive main class:

package logging.log4j2;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MainApp {

    private final Log LOG = LogFactory.getLog(MainApp.class);
    private final String[] commandLineArgs;

    public static void main(String[] args) {
        MainApp app = new MainApp(args);
        app.start();
    }

    protected MainApp(String[] args) {
        commandLineArgs = args;
    }

    public void start() {
        LOG.info("Starting MainApp application ...");

        // ... do main application stuff here
        LOG.debug("This is only for DEBUG mode.");
    }
}

Now the code for the developer wrapper main class:

package logging.log4j2;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.net.URL;

public class DevWrapperMainApp extends MainApp {

    private static final Log LOG = LogFactory.getLog(DevWrapperMainApp.class);
    public static final String PROP_LOG4J_CONFIGURATION_FILE = "log4j.configurationFile";

    protected DevWrapperMainApp(String[] args) {
        super(args);
    }

    public static void main(String[] args) {
        preconfigureDevMode();
        DevWrapperMainApp devApp = new DevWrapperMainApp(args);
        devApp.start();
    }

    private static void preconfigureDevMode() {
        LOG.debug("Preconfigure application for deveoper mode ...");
        String log4j2ConfigFilePath =    System.getProperty(PROP_LOG4J_CONFIGURATION_FILE);
        if(log4j2ConfigFilePath == null || log4j2ConfigFilePath.isEmpty()) {
            URL configResource = DevWrapperMainApp.class.getResource("/dev-log4j2.xml");
            if(configResource != null) {
                System.setProperty(PROP_LOG4J_CONFIGURATION_FILE, configResource.toExternalForm());
            } else {
                LOG.error("Set log4j2 configuration file property failed. Resource file could not be detected correctly.");
            }
        }
    }
}

The logging of the productive application is configured by the log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="productiveConfig" status="WARN" monitorInterval="5">
    <properties>
        <property name="log.pattern.layout">%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</property>
    </properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${sys:log.pattern.layout}"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

For the sample app there is no file appender but the logging level and the name of the configuration is different from the following dev-log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="developerConfig" status="DEBUG" monitorInterval="5">
    <properties>
        <property name="log.pattern.layout">DEV-MODE: %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</property>
    </properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${sys:log.pattern.layout}"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

By running the DevWrapperMainApp class I get the following output:

"C:\Program Files\Java\jdk1.8.0_66\bin\java" ...
11:40:14.553 [main] INFO  logging.log4j2.MainApp - Starting MainApp application ...

Process finished with exit code 0

In addition to the INFO logging I expected the output of the DEBUG logging as well. Therefore the log configuration seems not to be reconfigured by override the system property at that moment. Maybe it is to late and log4j2 is allready configured by the productive configuration file? How can I change the whole configuration at the startup time of my application? The documentation says:

However, should any logging be attempted before Configurator.initialize() is called then the default configuration will be used for those log events. (Part: Reconfigure Log4j Using ConfigurationBuilder with the Configurator

Maybe somebody has a hint for me to go in the right direction? I also know the possibility to create a log4j2-test.xml for the developing purpose but a want to avoid this and also to set the system property. The code should be known where to find the configuration file.

Thanks in advance.

Hardie

1 Answer 1

1

Log4j 2 supports having a separate configuration for testing. You can have two configuration files, one named log4j2.xml for production, and one named log4j2-test.xml for testing. If both exist Log4j 2 will use the test configuration. In production you simply don't deploy the test configuration. See the docs for the exact order in which Log4j 2 initializes.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.