Tomcat 8.5下Spring应用Log4j日志输出位置异常排查
问题根因分析
这个问题本质是Tomcat默认日志体系和应用内SLF4J日志门面绑定冲突,结合Tomcat类加载机制差异导致的,具体原因如下:
- 首先明确Tomcat默认日志文件的定位:
catalina.out是Tomcat全局的标准输出/标准错误(stdout/stderr)收集文件,所有输出到控制台的内容都会写入该文件;而localhost.log是Tomcat JULI日志实现专门收集localhost主机下Web应用JUL(java.util.logging)日志的文件。 - 你使用SLF4J作为日志门面,SLF4J运行时会自动扫描类路径下的绑定实现包,绑定优先级完全取决于类加载顺序。如果你的应用
WEB-INF/lib目录下同时存在slf4j-log4j12(Log4j绑定包)和slf4j-jdk14(JUL绑定包),两个类所在包的加载顺序差异,会导致它们绑定到不同的日志实现:com.foo.foo2.B类加载时,SLF4J先扫描到slf4j-log4j12绑定,日志走你配置的ConsoleAppender输出到stdout,最终写入catalina.outcom.foo.foo1.A类加载时,SLF4J先扫描到slf4j-jdk14绑定,日志走JUL实现,被Tomcat的JULI接管后输出到localhost.log
- 还有两种低概率触发场景:
- 你贴出的
log4j.properties不是应用实际加载的配置,类路径下存在其他隐藏的log4j配置,单独为com.foo.foo1包配置了JUL输出规则,没有继承rootLogger的stdout输出 - Tomcat全局
lib目录下存在日志相关的冲突包,父类加载器优先加载了JUL绑定实现,刚好com.foo.foo1包的类被父类加载器优先加载,导致绑定异常
- 你贴出的
验证&修复方案
- 先检查应用的SLF4J绑定包,执行命令
ls WEB-INF/lib | grep slf4j,如果同时存在slf4j-log4j12和slf4j-jdk14,直接删除slf4j-jdk14包即可解决问题 - 若绑定包无异常,可在两个类的Logger实例化后增加一行打印:
System.out.println(logger.getClass().getName());,如果A类输出org.slf4j.impl.JDK14Logger、B类输出org.slf4j.impl.Log4jLoggerAdapter,即可确认是绑定冲突问题 - 排查类路径下是否有其他未覆盖到的log4j配置文件,删除多余配置即可
内容的提问来源于stack exchange,提问作者yln snow
相关产品推荐
相关产品推荐

