在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>