Днес имам проблем да преконфигурирам правилно конфигурацията на log4j2. За да обясня проблема, създадох примерно приложение, което съответства почти на нашия продуктивен код. Примерната структура на проекта е показана на следната снимка:
За целите на разработчиците искаме да стартираме основното приложение с клас обвивка, за да конфигурираме някакъв параметър като конфигурация на регистриране или системни свойства, които не трябва да се поставят в продуктивния код. Следователно продуктивната конфигурация log4j2 трябва да бъде заменена от тази за разработчици, за да се зададе по-специфично нивото на регистрационния файл и да се избегне добавянето на файлове към записите в журнала. Следва кодът за продуктивния основен клас:
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.");
}
}
Сега кодът за главния клас на обвивката на разработчиците:
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.");
}
}
}
}
Регистрирането на продуктивното приложение се конфигурира от 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>
За примерното приложение няма приложение за добавяне на файлове, но нивото на регистриране и името на конфигурацията е различно от следното 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>
Като стартирам класа DevWrapperMainApp, получавам следния резултат:
"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
В допълнение към регистрирането на INFO, очаквах изхода и от регистрирането на DEBUG. Следователно конфигурацията на регистрационния файл изглежда не е преконфигурирана чрез замяна на системното свойство в този момент. Може би е твърде късно и log4j2 вече е конфигуриран от продуктивния конфигурационен файл? Как мога да променя цялата конфигурация в момента на стартиране на моето приложение? В документацията се казва:
Въпреки това, ако се направи опит за регистриране, преди Configurator.initialize() да бъде извикан, тогава конфигурацията по подразбиране ще се използва за тези регистрационни събития. (Част: Преконфигуриране на Log4j с помощта на ConfigurationBuilder с конфигуратора
Може би някой има намек да тръгна в правилната посока? Знам също възможността за създаване на log4j2-test.xml за целите на разработването, но искам да избегна това и да задам системното свойство. Кодът трябва да се знае къде да се намери конфигурационният файл.
Благодаря предварително.
Харди