让log4j支持占位符

让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

你可能感兴趣的:(让log4j支持占位符)