Log4j Commons Logging Bridge失效 部分Tomcat9实例FOP日志写入catalina.out求助
问题排查与解决建议
优先排查类加载顺序差异(部分服务器异常的核心诱因)
Tomcat多实例环境下即使软件包、系统配置完全一致,也可能因为类加载路径优先级、类加载委派规则的微小差异导致commons-logging加载了错误的实现类:
- commons-logging自动探测不到桥接实现时会默认使用
org.apache.commons.logging.impl.SimpleLog,该实现默认直接输出到stderr,不会触发Log4j的日志事件,所以开启Configuration status="trace"也不会有相关报错,符合观测到的现象。 - 排查是否存在重复的commons-logging相关Jar包:
检查Tomcat/lib目录、应用WEB-INF/lib目录下是否同时存在原生commons-logging.jar和log4j-jcl.jar,如果Tomcat全局lib目录下存在commons-logging的原生Jar,会优先于应用内的log4j-jcl桥接包加载,导致桥接失效。
可在出问题的实例上执行命令排查Jar包冲突:# 扫描Tomcat全目录的commons-logging相关Jar find ${CATALINA_HOME} -name "commons-logging*.jar" -o -name "log4j-jcl*.jar" - 强制指定commons-logging的工厂实现类:
直接在应用的启动参数中添加JVM系统属性,强制commons-logging使用log4j-jcl的实现,避免自动探测失败:
也可以在应用的-Dorg.apache.commons.logging.LogFactory=org.apache.logging.log4j.jcl.LogFactoryImplWEB-INF/classes目录下添加commons-logging.properties配置文件,内容为:org.apache.commons.logging.LogFactory=org.apache.logging.log4j.jcl.LogFactoryImpl
排查fop组件的日志实现选择优先级
fop组件本身支持自定义日志实现选择,部分环境下会优先使用自身的简易日志实现输出到stderr,可添加JVM启动参数指定fop的日志实现绑定log4j2:
-Dorg.apache.fop.logger=log4j2
验证类加载来源
在出问题的实例上添加调试代码,打印异常场景下org.apache.commons.logging.LogFactory的实际加载来源,确认是否为log4j-jcl提供的实现:
System.out.println(LogFactory.class.getProtectionDomain().getCodeSource().getLocation()); System.out.println(LogFactory.getFactory().getClass().getProtectionDomain().getCodeSource().getLocation());
注:部分服务器如果开启了Tomcat的委派类加载模式(
delegate="true"),也会导致应用内的桥接包无法被优先加载,可对比正常/异常实例的conf/context.xml配置中的Loader节点属性是否一致。
内容的提问来源于stack exchange,提问作者Hok
相关产品推荐
相关产品推荐

