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 FileApp开发者_开发技巧ender 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.
You can load it manually:
Properties props = new Properties();
InputStream fis = new FileInputStream(new File("/somewhere/log4j.properties"));
props.load(fis);
fis.close();
PatternLayout layout = new PatternLayout(props.getProperty("file_pattern"));
精彩评论