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:
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
