Log4j Commons Logging Bridge 被忽略

Log4j Commons Logging Bridge ignored

我们的网络应用程序在 tomcat 9 容器中运行,并使用 Log4j 2.13.3 作为日志系统。

Web 应用程序包括 org.apache.xmlgraphics:fop 2.3,它使用 apache commons-logging(我们设置中的版本 1.2 而不是 fop 中最初使用的 1.0.4) .

这种组合 运行 多年来一直使用 log4-jcl、Commons Logging Bridge,并且所有 commons-logging 输出都正确地进入了 log4j 配置的文件中。配置相当简单,如

所述

然而,没有明显的原因,fop 最近开始将其所有(相当冗长的)日志写入 stderr(即直接写入 catalina.out)而不是配置的日志文件,但仅限于 一些 我们的系统。我们有大约 50 tomcat 个实例 运行 基本相同的软件和相同的系统配置;其中三分之一仍然正确记录。

我假设 commons-logging 没有找到 log4j-jcl 的 org.apache.commons.logging.LogFactory 实现。

使用 Configuration status="trace" 调试 log4j 不会在 log4j-jcl 或其他地方提供任何失败提示。

我疯了。有什么建议吗?

回答我自己的问题以防对其他人有帮助。

我需要在 class 路径中添加一个名为 commons-logging.properties 的文件,其中包含一行:

org.apache.commons.logging.LogFactory=org.apache.logging.log4j.jcl.LogFactoryImpl

感谢 Piotr 关于设置 org.apache.commons.logging.diagnostics.dest 的评论。

显然,如果未明确指定 class,则实际使用的 LogFactory 的实现取决于 classloader 加载潜在候选者的(有点随机)顺序。

我的 webapp 的一个 maven 依赖项带来了 sl4f 作为传递依赖项,所以在某些系统上选择了 slf4j 而不是 log4j,但是 slf4 没有有效的配置并且默认为 STDERR。

虽然您的回答解释了为什么未选择 Log4j 2.x 作为 JCL 的后端,但有些细节并没有加起来:原来的 commons-logging never 选择SLF4j 作为后端(参见 source code)。所以情况一定更复杂:

  • 最初的 commons-logging 通过 ServiceLoader 实用程序发现了替代 LogFactory 实现。
  • 您的 class 路径中必须有两个替代 LogFactory 实现:log4j-jcl and spring-jcl. The latter is a complete replacement for the standard commons-logging library (i.e. it contains a copy of org.apache.commons.logging.LogFactory itself) and has some complex backend selection rules (cf. source code),在您的情况下,它更喜欢 SLF4J 而不是 Log4j 2.x.

由于 classloader 从 commons-loggingspring-jcl 随机加载 org.apache.commons.logging.LogFactory class 你可能有两种问题:

  1. 如果选择 commons-logging 版本,ServiceLoader 会随机加载 log4j-jcl 的实现或 spring-jcl 的实现。您已经在您的回答中解决了这个问题。
  2. 如果选择 spring-jcl 的版本,将使用 SLF4J 后端。

为了解决所有这些潜在的问题,我会:

  1. 删除原始 commons-logging 并保留克隆 spring-jcl。更好的是,我会排除两者并使用确定性 jcl-over-slf4j(始终使用 SLF4J 的完整 JCL 替换)
  2. 删除log4j-jcl,因为不再需要它(只有原来的commons-logging需要),
  3. 添加 log4j-slf4j-impl SLF4J 绑定。

此解决方案向您的日志记录配置添加了额外的 API(JCL -> SLF4J -> Log4j 2.x),但保证了稳定性。这也是 spring-boot-starter-log4j2 的工作方式。