stone2083

让log4j支持占位符

目标:让log4j.xml配置文件中允许使用占位符(${key}).

使用场景:
在运行期决定一些动态的配置内容.
比如在我们项目中,希望一台物理机同一个应用跑多个实例.
因为多进程操作同一份log文件存在并发问题(打印,DailyRolling等),所以我希望配置如下:${loggingRoot}/${instance}/project.log
在运行脚本中,通过加入-Dinstance=instance1参数,来动态指定实例名.让同一份应用在不同的运行实例下,日志打印到不同的路径

Log4j分析:
我以为,Log4j天生就支持占位符的.请见:org.apache.log4j.helpers.OptionConverter.substVars(String val, Properties props)就有对占位符的处理.
org.apache.log4j.PropertyConfigurator (log4j.properties文件解析).默认就支持对占位符的处理.
org.apache.log4j.xml.DOMConfigurator挺怪异的.明明也有对占位符的处理.但是我们就是无法对其属性props进行赋值.
(当然,有可能是我误解了其props的用法--还没有完整读过他的源码)

处理方案:
继承org.apache.log4j.xml.DOMConfigurator,实现自己的DOMConfigurator.
public class PlaceHolderDOMConfigurator extends org.apache.log4j.xml.DOMConfigurator {

    
private Properties props;

    
public PlaceHolderDOMConfigurator(Properties props){
        
this.props = props;
    }

    
public static void configure(String filename, Properties props) {
        
new PlaceHolderDOMConfigurator(props).doConfigure(filename, LogManager.getLoggerRepository());
    }

    //主要是覆写这个方案.传入properties对象
    
protected String subst(String value) {
        
try {
            
return OptionConverter.substVars(value, props);
        } 
catch (IllegalArgumentException e) {
            LogLog.warn(
"Could not perform variable substitution.", e);
            
return value;
        }
    }
}

测试代码:
log4j.xml片段:
<appender name="PROJECT" class="org.apache.log4j.DailyRollingFileAppender">
        
<param name="file" value="${loggingRoot}/${instance}/project.log"/>
        
<param name="append" value="false"/>
        
<param name="encoding" value="GB2312"/>
        
<param name="threshold" value="info"/>
        
<layout class="org.apache.log4j.PatternLayout">
            
<param name="ConversionPattern" value="%d [%X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/>
        
</layout>
    
</appender>
Run.java:
public static void main(String[] args) {
        Properties props 
= new Properties();
        props.setProperty(
"loggingRoot""d:/tmp");
        props.setProperty(
"instance""instance1");

        PlaceHolderDOMConfigurator.configure(LOG4J_PATH, props);
        Logger rootLogger 
= LogManager.getRootLogger();
        FileAppender fileAppender 
= (FileAppender) rootLogger.getAppender("PROJECT");
        System.out.println(fileAppender.getFile());
    }

输出结果:
d:/tmp/instance1/project.log

当然,你也可以通过在启动参数中加 -DloggingRoot=xxxx  -Dinstance=yyyy动态指定内容.


特别说明:
本文:log4j版本为1.2.14
log4j 1.2.15测试不通过,原因见:https://issues.apache.org/bugzilla/show_bug.cgi?id=43325

posted on 2010-07-01 08:52 stone2083 阅读(12589) 评论(2)  编辑  收藏 所属分类: java

Feedback

# re: 让log4j支持占位符[未登录] 2012-10-27 13:41 dd

setParameter  回复  更多评论   

# re: 让log4j支持占位符[未登录] 2012-10-27 13:42 dd

重载setParameter才兼容所有  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: