在Web应用中Log4j与JNDI结合1 – JNDI指定配置文件一文中,我展示了如何通过定制ServletListener来从JNDI指定地址读取log4j配置文件。这一篇我来讲解如何通过JNDI指定日志路径。普通的log4j appender没有办法处理JNDI相关的日志文件。同ServletListener定制一样,我们要定制Appender。这里以DailyRollingFileAppender为例。普通按照天来自动截断,例如:
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="default.log" />
<param name="append" value="false" />
<param name="datePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} [%-5p] [%t] [%c{1}] %m%n" />
</layout>
</appender>
通过Log4j源码分析(org.apache.log4j.LogManager.java, org.apache.log4j.xml.DOMConfigurator.java and DailyRollingFileAppender.java),我们可以知道,在Web应用XML的配置方式下,LogManager.java的static初始化块会根据log4j.configuration的配置,通过org.apache.log4j.helpers.OptionConverter.selectAndConfigure方法找到对应的log4j xml配置文件,然后通过Call org.apache.log4j.xml.DOMConfigurator.java的doConfigure方法,去到parse方法,根据Logger和Root node的APPENDER_REF_TAG调用findAppenderByReference,最后在parseAppender 中把param配置赋值给appender的属性,然后通过调用appender的activeOptions来打开日志记录文件。
DailyRollingFileAppender.java
public void setFile(String file) {
// Trim spaces from both ends. The users probably does not want
// trailing spaces in file names.
String val = file.trim();
fileName = val;
}
public void activateOptions() {
//based on fileName to open log file
super.activateOptions();
if(datePattern != null && fileName != null) {
now.setTime(System.currentTimeMillis());
sdf = new SimpleDateFormat(datePattern);
int type = computeCheckPeriod();
printPeriodicity(type);
rc.setType(type);
File file = new File(fileName);
scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
} else {
LogLog.error("Either File or DatePattern options are not set for appender ["
+name+"].");
}
}
那么想通过jndi来指定日志文件,就是要给修改对filename赋值。简单实现可以通过继承DailyRollingFileAppender,在新的子类(JndiDailyRollingFileAppender )中加入新的属性jndiDirURL来接受JNDI指定日志路径文件夹(在xml配置中必须放在file参数之前),然后重写filename赋值的setFile方法,获取基于JNDI的完整文件路径。列出参考代码如下:
public class JndiDailyRollingFileAppender extends DailyRollingFileAppender {
private String jndiDirURL;
public void setJndiDirURL(String jndiDirURL){
this.jndiDirURL= jndiDirURL;
}
public String getJndiDirURL(){
return this.jndiDirURL;
}
public JndiDailyRollingFileAppender (String jndiDirURL, Layout layout, String filename, String datePattern) throws IOException {
super(layout, getAbsoluteName(jndiDirURL,filename), datePattern);
}
private String getAbsoluteName(String filename){
try{
Context ic = new InitialContext();
String parent= ((URL)ic.lookup(jndiDirURL)).toExternalForm();
String absolutePath = parent + File.separator + filename;
return absolutePath;
}catch(Exception e){
LOG.error("unable to find jndidirurl: {}, JndiDirURL);
return filename;
}
}
@Override
public void setFile(String file) {
return super.setFile(getAbsoluteName(file));
}
}
对应的log4j.xml中的配置文件如下:
<appender name="default" class="com.demo.JndiDailyRollingFileAppender">
<param name="jndiDirURL" value="java:comp/env/demo_log" />
<param name="file" value="default.log" />
<param name="append" value="false" />
<param name="datePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} [%-5p] [%t] [%c{1}] %m%n" />
</layout>
</appender>