Log4j 1.2.15路径替换一个bug

    Log4j提供了一个路径替换(subst-mechanism)功能,可以实现运行期替换log4j配置文件里${xx}的标记为外部指定的值。
    例如:log4j.xml可以指定file的值为"${loggingRoot}/project.log",此时就可以利用log4j的subst功能,把${loggingRoot}替换成具体的路径,如d:/app/logs

<appender name="PROJECT" class="log4j.DailyRollingFileAppender">
        <param name="file" value="${loggingRoot}/project.log"/> 
<param name="append" value="true"/> 
<param name="encoding" value="GBK"/>
        <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>

 

 

    那怎么在自己的应用里实现呢? 我们看看org.apache.log4j.xml.DOMConfigurator的类图,发现它提供了一个protected String subst()方法,protected是一个很好的暗示,它暗示着我们可以重载此方法,用自己的props。看看自己写的类吧:

 

    log4j的DOMConfigurator的subst实现

/**
     * Substitutes property value for any references in expression.
     *
     * @param value value from configuration file, may contain
     *              literal text, property references or both
     * @return evaluated expression, may still contain expressions
     *         if unable to expand.
     */
    protected String subst(final String value) {
        try {
            //props是DOMConfigurator的一个成员变量
            return OptionConverter.substVars(value, props);
        } catch (IllegalArgumentException e) {
            LogLog.warn("Could not perform variable substitution.", e);
            return value;
        }
    }

 

 

 

public class DOMConfigurator extends org.apache.log4j.xml.DOMConfigurator {
    private Properties props;

    /**
     * 创建新对象。
     */
    public DOMConfigurator() {
        this(null);
    }

    /**
     * 创建新对象。
     *
     * @param props 可在配置文件中被引用的属性
     */
    public DOMConfigurator(Properties props) {
        this.props = props;
    }
    
    /**
     * 使用XML文件配置log4j。
     *
     * @param filename 配置文件名
     * @param props 可在配置文件中被引用的属性
     */
    public static void configure(String filename, Properties props) {
        new DOMConfigurator(props).doConfigure(filename, LogManager.getLoggerRepository());
    }
    /**
     * 设置属性,这些属性可以在配置文件中被引用。
     *
     * @param props 属性
     */
    public void setProperties(Properties props) {
        this.props = props;
    }

    /**
     * 替换字符串值,将其中的${xxx}替换成具体的值。
     *
     * @param value 要替换的值
     *
     * @return 替换后的值
     */
    protected String subst(String value) {
        try {
            return OptionConverter.substVars(value, props);
        } catch (IllegalArgumentException e) {
            LogLog.warn("Could not perform variable substitution.", e);
            return value;
        }
    }
}

 

 

   忽然某一天,你发现这个功能不能用了,想了半天,哪也没改吗? 没办法,Debug吧,找问题根源的利器,最后你发现别人升级了log4j的版本,log4j 1.2.15。 那就对了,这是log4j-1.2.15的一个bug,它导致了路径替换功能的失效,因为1.2.15版本的DOMConfigurator又提供了一套static的方法实现,如下面为它的代码:

protected  void setParameter(Element elem, PropertySetter propSetter) {
      //调用static方法,这里的props变成了log4j内部DOMConfigurator的成员变量,它现在是null
      setParameter(elem, propSetter, props);
  }
 public static void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
        //传递props到static subst,到此路径替换就失效了
     String name = subst(elem.getAttribute("name"), props);
        String value = (elem.getAttribute("value"));
        value = subst(OptionConverter.convertSpecialChars(value), props);
        propSetter.setProperty(name, value);
}

public static String subst(final String value, final Properties props) {
        try {
            return OptionConverter.substVars(value, props);
        } catch (IllegalArgumentException e) {
            LogLog.warn("Could not perform variable substitution.", e);
            return value;
        }
}

 

  在1.2.16后的版本已经解决了此问题,官网还有此bug的记录:https://issues.apache.org/bugzilla/show_bug.cgi?id=43325

   Log4j的路径替换很好用,有点类似它内置的MDC功能,从而帮助我们分离开发、生产环境的配置。

 

----以下无内容----

你可能感兴趣的:(apache,maven,log4j,xml,配置管理)