概述
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功能,从而帮助我们分离开发、生产环境的配置。
----以下无内容----
最后
以上就是典雅铅笔为你收集整理的Log4j 1.2.15路径替换一个bug的全部内容,希望文章能够帮你解决Log4j 1.2.15路径替换一个bug所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复