Log4J appears to have an annoying restriction – at runtime, variable substitution does not appear to work.
In this example
File: Log4j.properties
file_pattern=%d{ISO8601} %-5p %m%n
log4j.rootLogger=DEBUG, FileAppender
log4j.appender.FileAppender=org.apache.log4j.FileAppender log4j.appender.FileAppender.layout=org.apache.log4j.PatternLayout log4j.appender.FileAppender.layout.ConversionPattern=${file_pattern} log4j.appender.FileAppender.File=log4jtest1.log
log4j.appender.FileAppender.Threshold=ERROR
The FileAppender configured in the log4j.properties file produces the correct output:
File: log4jtest1.log
ERROR Sample error message FATAL Sample fatal message
If I attempt to create a FileAppender at runtime
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
public class Main {
static final Logger logger = Logger.getLogger(Main.class);
public static void main(String[] args) throws Exception {
FileAppender appender = new FileAppender();
appender.setFile("log4test2.log");
PatternLayout pl = new PatternLayout("${file_pattern}");
appender.setLayout(pl);
appender.setName("log4jtest2");
appender.setThreshold(Level.ERROR);
appender.activateOptions();
logger.addAppender(appender);
logger.trace("Sample trace message");
logger.debug("Sample debug message");
logger.info("Sample info message");
logger.warn("Sample warn message");
logger.error("Sample error message");
logger.fatal("Sample fatal message");
}
}
Te output is
File: log4jtest2.log
${file_pattern}${file_pattern}
Can anyone explain what is the problem and how can it be fixed?
Related question: Can an application access the ResourceBundle in order to read variables intended to be substituted?
Variable substitution is a feature of PropertyConfigurator not of PatternLayout. If you look at your code, you never define what file_pattern should be. But why would you need variable substitution in code? Just do this:
PatternLayout pl = new PatternLayout("%d{ISO8601} %-5p %m%n");
If you want to reference that string somewhere else, just make it a constant.
Edit: You will have to read the properties object, but PropertyConfigurator can take a properties object instead a file, so you could load that, do what you need to do and pass it on to the PropertiesConfigurator, so you only have one configuration path.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With