Reputation: 548
I am doing the upgrade work from log4j1.2.17 to log4j2.12.0. I need to implement the features what we has done with log4j1.x. However, I'm having some tough problems:
In log4j1.x, after extends class FileAppender
, I can use org.apache.log4j.FileAppender#setFile
to modify the current output file. How to setFile in log4j2 ?
In log4j1.x, by org.apache.log4j.xml.DOMConfigurator#doConfigure
I can do the configuration incrementally. How to do that in log4j2 ?
The scenario as follow :
Firstly, I built the basic log4j2 configuration (logger apper layout) wit API. Then I want to use the file log4j2-new.xml to update the configuration incrementally based on the previous configuration.
update:
For the question2, the backgroung is as following:
I configure the basic logging system with a few XML. However, there is another module called reportService needs to programmatically create some loggers to write report data to files. The basic logging system needs to support hot deployment, which means that the logger needs to be refreshed when the xml changes without removing the loggers create by reportService. I have read the manual of log4j2. And I tried CompositeConfiguration
, but It seems the class can't take the config from ((LoggerContext) LogManager.getContext(false)).getConfiguration()
as parameter. I think the reason is CompositeConfiguration can't use config that has called initialize()
. Here is a example (I use log4j2-base.xml to simulate creating loggers programmatically )
public class LoadXmlConfigurationTest {
public static final String BASE_CONFIG = "log4j2-base.xml";
public static final String EXT_CONFIG = "log4j2-ext.xml";
@Test
public void loadXmlConfigTest() {
System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, BASE_CONFIG);
Configuration baseConfig = ((LoggerContext) LogManager.getContext(false)).getConfiguration();
final Configuration extConfig = loadConfiguration("log4j2-ext.xml");
List<AbstractConfiguration> configs = new ArrayList<>();
configs.add((AbstractConfiguration) baseConfig);
configs.add((AbstractConfiguration) extConfig);
CompositeConfiguration compositeConfiguration = new CompositeConfiguration(configs);
((LoggerContext) LogManager.getContext(false)).reconfigure(compositeConfiguration);
Logger logger = LogManager.getLogger("EXT");
Logger rootLogger = LogManager.getRootLogger();
logger.error("ext logger info");
rootLogger.error("root logger info");
}
private Configuration loadConfiguration(final String resourcePath) {
try (final InputStream in = getClass().getClassLoader().getResourceAsStream(resourcePath)) {
return new XmlConfiguration(new LoggerContext("test"), new ConfigurationSource(in));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
output is as follow, the baseConfig doesn't work:
2020-03-01 10:26:41,394 main ERROR No logging configuration
EXT | 2020-03-01 10:26:41,411 ERROR [main] (LoadXmlConfigurationTest.java:50) - ext logger info
10:26:41.413 [main] ERROR - root logger info
log4j2-base.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="ROOT" target="SYSTEM_OUT">
<PatternLayout>
<pattern>ROOT | %d %-5p [%t] %C{2} (%F:%L) - %m%n</pattern>
</PatternLayout>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="ROOT" />
</Root>
</Loggers>
</Configuration>
log4j2-ext.xml
log4j
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="EXT" target="SYSTEM_OUT">
<PatternLayout>
<pattern>EXT | %d %-5p [%t] (%F:%L) - %m%n</pattern>
</PatternLayout>
</Console>
</Appenders>
<Loggers>
<Logger name="EXT" level="DEBUG" additivity="false">
<AppenderRef ref="EXT" />
</Logger>
</Loggers>
</Configuration>
Upvotes: 0
Views: 1018
Reputation: 9151
When migrating from Log4j 1 to Log4j 2 too often people just look at the customizations they made for Log4j 1 and try to port them to Log4j 2. This is absolutely the wrong approach.
When migrating from Log4j 1 to Log4j 2 your first step should be to gather what your requirements are for logging. Once you have those you should look at how Log4j 2 could natively implement that. Log4j 2 contains many features that were not available in Log4j 1 and its architecture is very different.
It also would be very difficult to answer your questions above without knowing what you are trying to accomplish. Are you trying to change the file name while the configuration is running? In Log4j 2 the file name is immutable in the File Appender because it can't be changed in a thread-safe manner. You can, however, create a new Configuration with a new FileAppender configured to point to a new file.
What do you mean by "incrementally"? Log4j 2 lets your programmatically create a configuration in a few various ways. Log4j's Programmatic Configuration page documents how to do that. What does it mean you want to use log4j2-new.xml to update the configuration incrementally? Are you wanting to add to the configuration or replace it? Log4j allows composite configurations so you can merge configurations. You would first create your configuration, then the XMLConfiguration, merge them together in a CompositeConfiguration and then pass that to one of the Configurator classes Configurator methods. However, this may make it difficult for you to allow automatic configuration should the configuration file need to be changed.
Frequently people find that they do not need programmatic configuration. Log4j provides Appenders that dynamically create other appenders, a PatternSelector that lets you format records based on attributes in the log event, Lookups that let you dynamically inject values into your configuration at run time, and other features.
So again, before embarking on migrating from Log4j 1 to Log4j 2 first evaluate your requirements and then look at Log4j 2's existing features to determine who to meet them. If you have questions about that feel free to ask here on Stackoverflow or email the Log4j user's mailing list.
Upvotes: 2