Best way to initialize log4j2 (TWO) programmatically
This is what I am doing to load the log4j2.xml file by specifying the location of the log file from another properties file to make the configuration easier to maintain:
MyProperties props = MyProperties.getInstance();
System.setProperty(MyConstants.AUDIT_LOG_ENV_VAR,
props.getAuditLogFileName());
ConfigurationSource source =
new ConfigurationSource(new FileInputStream(new File(
System.getProperty(MyConstants.PROPERTIES_FILE_ENV_VAR)
+ "/log4j2.xml")));
Configurator.initialize(null, source);
and log4j2 will take and use my filename because I specified it in Appender using the envvar replacement:
<File name="AuditLogger" fileName="${sys:AUDIT_LOG}">
<PatternLayout pattern="DATETIME %d{yyyy-MM-dd HH:mm:ss:SSS zzz}%n%msg%n" />
</File>
However, I don't like this because there is a smell in squeezing the value of the filename into the system environment before reading it again on the next line of code.
I like to programmatically program log4j2 using the ConfigurationFactory , but it looks like a similar way cannot be built on top of the log4j2.xml file - or is there
source to share
Usually the log4j2 team does not recommend programming configuration: the separation between the api and core jars should give developers a clear separation between API and implementation. The software configuration depends on implementation details, so it may be broken in a future version.
If there is anything that cannot be done with the customization, please let us know so we can improve it.
For your specific use case: it looks like you want to set a system property to a specific value before log4j2 initializes itself based on that value. If it's a standalone application, one way to avoid getting stuck in the details of a log4j2 implementation is to set all the required system properties before referencing any log4j2 classes:
public class MainWrapper {
public static void main(String[] args) {
System.setProperty("key", "value");
// ...
ActualMain.main(args); // delegate to the actual start of the application
}
}
An alternative that I would like to draw your attention to is to create your own custom search. This can be done in a few lines of code with the log4j2 plugin . It also depends on some implementation details, but the result is more powerful and reusable.
package com.mycompany;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.AbstractLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
/** Looks up keys in MyProperties singleton. */
@Plugin(name = "MyProperties", category = StrLookup.CATEGORY)
public class MyPropertiesLookup extends AbstractLookup {
@Override public String lookup(final LogEvent event, final String key) {
return MyProperties.getInstance().getValue(key);
}
}
Then in your configuration, you can use your own search instead of system properties:
<File name="AuditLogger" fileName="${MyProperties:AUDIT_LOG}">
<PatternLayout pattern="DATETIME %d{yyyy-MM-dd HH:mm:ss:SSS zzz}%n%msg%n" />
</File>
source to share