如何将 java.util.logging 发送到 log4j?

Posted

技术标签:

【中文标题】如何将 java.util.logging 发送到 log4j?【英文标题】:How to send java.util.logging to log4j? 【发布时间】:2010-10-26 13:52:07 【问题描述】:

我有一个现有的应用程序,它针对 log4j 执行所有日志记录。我们使用了许多其他库,这些库要么也使用 log4j,要么针对 Commons Logging 进行记录,最终在我们的环境中使用 log4j。我们的依赖项之一甚至针对 slf4j 进行日志记录,这也可以正常工作,因为它最终也会委托给 log4j。

现在,我想为这个应用程序添加 ehcache 以满足一些缓存需求。以前版本的 ehcache 使用 commons-logging,在这种情况下可以完美运行,但是从 version 1.6-beta1 开始,他们已经删除了对 commons-logging 的依赖,并用 java.util.logging 代替了它。

不太熟悉 java.util.logging 提供的内置 JDK 日志记录,有没有一种简单的方法可以将发送到 JUL 的任何日志消息记录到 log4j 中,这样我就可以使用我现有的配置并设置任何来自 ehcache 的日志记录?

查看 JUL 的 javadocs,看起来我可以设置一堆环境变量来更改使用哪个 LogManager 实现,也许用它来将 log4j Loggers 包装在 JUL Logger 类中.这是正确的方法吗?

具有讽刺意味的是,当世界其他地方(大部分)使用 3rd 方库时,库使用内置 JDK 日志记录会引起如此头痛。

【问题讨论】:

对于 Log4j 2,请参阅 ***.com/q/21781026 【参考方案1】:

我成功使用的一种方法是使用slf4j 作为我的主要日志记录 API。然后我将 slf4j 绑定到 log4j。使用其他框架(如 JUL)的 3rd 方依赖项可以是 bridged to slf4j。

【讨论】:

很好的链接,但我认为你的意思是#jul-to-slf4j 这听起来不错,但我似乎无法让它发挥作用:( 另外,我不敢相信像 ehcache 这样流行的库会切换到 java.util.logging 之类的东西——看起来很愚蠢 @matt b,JUL 始终存在于 Java 运行时中,因此它需要最少的外部依赖。然而,在我看来,这是一个由没有使用该代码经验的人编写的代码的真实示例。配置系统比较不方便。 您遇到的问题是,如果您将 SLF4J 桥接到 JUL,则日志记录性能令人震惊。具体来说,您创建的每个日志行都会引发异常,以确定要使用的记录器上下文。这会产生大量开销并减慢进程【参考方案2】:

我相信 slf4j 站点有一个通过 slf4j 传递 java.util.logging 事件的桥梁(并因此传递给 log4j)。

是的,SLF4J 下载包含 jul-to-slf4j,我相信它就是这样做的。它包含一个将记录传递给 SLF4J 的 JUL 处理程序。

【讨论】:

【参考方案3】:

我们在当前项目中使用SLF4J,它对我们非常有效。 SLF4J 由 Log4J 的创建者 Ceki Gülcü 编写,他做得非常出色。在我们的代码中,我们直接使用 SLF4J 日志记录 API,我们配置 SLF4J 以便来自 Jakarta Commons Logging (JCL)、java.util.logging (JUL) 和 Log4J API 的调用都桥接到 SLF4J API。我们需要这样做,因为我们和您一样使用选择了不同日志记录 API 的第三方(开源)库。

在 SLF4J 的底部,您可以将其配置为使用特定的记录器实现。它带有一个内部或“简单”记录器,您可以使用 Log4J、JUL 或 Logback 覆盖它。只需在类路径中放入不同的 jar 文件即可完成所有配置。

最初,我们使用同样由 Ceki Gülcü 编写的 Logback 实现。这是非常强大的。但是,我们随后决定将我们的应用程序部署到 Glassfish Java EE 应用程序服务器,其日志查看器需要 JUL 格式的消息。所以今天我从 Logback 切换到了 JUL,在短短几分钟内,我将两个 Logback jar 替换为一个将其连接到 JUL 实现的 SLF4J jar。

就像@overthink 一样,我衷心推荐在您的设置中使用 SLF4J。

【讨论】:

Ceki 需要多少次重新发明日志框架/门面? @mP:日志记录可能不光彩,但它是大规模商业级软件的关键需求。 SLF4J 解决了集成使用不同日志框架的代码的问题(由于 Sun 选择开发 java.utils.logging 而不是采用 Log4J,这变得更加紧迫)。 @mP,slf4j 是必要的,因为 Sun 在 JUL 上做得不好。 Logback 是 log4j 的一个分支,而不是一个新项目。 我发现 logback 是必要的,如果没有别的,它不是 Apache,它实际上已经记录在案了。【参考方案4】:

@Yishai - 感谢您将链接发布到我的 wiki。那里的示例将 JUL 重定向到 Log4J,我已经让它在生产系统中运行了几年。 JBoss 5.x 已经将 JUL 重定向到 Log4J,所以我在升级时将其取出。我有一个更新的重定向到 SLF4J,我现在在一些事情上使用它。当我有机会时,我会发布。

但是,SLF4J 已经有了它:

http://mvnrepository.com/artifact/org.slf4j/jul-to-slf4j

【讨论】:

【参考方案5】:

有一个比 SLF4J 更简单的替代方法来桥接 JUL 和 log4j,请参阅 http://people.apache.org/~psmith/logging.apache.org/sandbox/jul-log4j-bridge/examples.html

您只需将 jul-log4j-bridge 放在类路径上并添加系统属性:

-Djava.util.logging.manager=org.apache.logging.julbridge.JULBridgeLogManager

jul-log4j-bridge 不在 Maven Central 中,可以从此存储库中获取:

<repository>
  <id>psmith</id>
  <url>http://people.apache.org/~psmith/logging.apache.org/repo</url>
  <releases>
    <enabled>false</enabled>
  </releases>
</repository>

然后用于:

<dependency>
  <groupId>org.apache.logging</groupId>
  <artifactId>apache-jul-log4j-bridge</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>log4j</groupId>
      <artifactId>apache-log4j-component</artifactId>
    </exclusion>
  </exclusions>
</dependency>

也可以通过以下步骤从源代码重建它:

    svn cohttp://svn.apache.org/repos/asf/logging/sandbox/jul-to-log4j-bridge/ 编辑 pom.xml,将 log4j:log4j:1.2.15 的依赖替换为 log4j:apache-log4j-extras:1.2.17 并删除对 apache-log4j-component 的依赖 mvn 包

【讨论】:

我认为它更简单,因为它可以在不更改代码的情况下完成,您只需添加一个系统属性。 SLF4J 还没有提出类似的机制,你要么更改代码,要么更改logging.properties 文件。 这在 log4j2 中不存在,不幸的是:( JulLog4jBridge.assimilate();o_0 警告! jul-log4j-bridge 使用从未发布的 apache-log4j-companions 捆绑包(来自废弃的 log4j 1.3 的反向移植)。您将很难构建它。当然,桥本身也被放弃了预发布。 @ivan_pozdeev 好点,谢谢。我已经添加了构建它的说明。【参考方案6】:

2014 年 10 月

由于 log4j 的 2.1 版存在组件 log4j-jul,它完全允许这样做。不过,如果您使用的是 log4j 1,则必须可以升级到 log4j2 才能使用这种方法。

JDK Logging Adapter

Class LogManager

Migrate from log4j 1.x to log4j 2

【讨论】:

截至目前(2018 年中),这应该是公认的答案 对于未来的读者:我确认这是有效的。因此,基本上(1)将其添加到您的 pom mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jul 和(2)在第一个链接中添加系统属性(例如,在 JVM 参数中添加 -Djava.util.logging.manager=org.apache.logging.log4j。 jul.LogManager ) 我注意到将它放在类路径中并不是只是在手动配置的 spring 中使用嵌入式 tomcat 9.0。你能提供步骤/代码吗?两个记录器都在工作,但 tomcat 显然没有使用 log4j 默认控制台附加程序。 最大的缺点是您必须“在对 LogManager 或 Logger 进行任何调用之前”设置系统属性(可能是它不适用于 @xenoterracide 的原因)。尤其是当您的项目依赖于其他项目时,这并不容易以理智的方式实现。另一种方法是使用 java.util.logging → SLF4J → Log4j 2。可能性能不是很好,但至少可以工作(SLF4J 桥有一些限制,因为它只实现了一个 java.util.logging 处理程序)。 Log4j 2 实际上有一个类似于 SLF4J 的 Log4jBridgeHandler 类,但它还没有被反向移植到 2.x,请参阅 backport pull request。【参考方案7】:

你应该在启动时手动添加自爆

SLF4JBridgeHandler.removeHandlersForRootLogger()
SLF4JBridgeHandler.install()

演示 -> https://gist.github.com/jiahut/654ecc75a13b0a1d8f3b4d5d2d69dc6d

【讨论】:

以上是关于如何将 java.util.logging 发送到 log4j?的主要内容,如果未能解决你的问题,请参考以下文章

如何映射 java.util.logging 和 SLF4J 记录器的级别?

Undertow java.util.logging:如何使用 java util logging 在运行时更改 undertow 服务器的日志记录级别

使用 java.util.logging 处理程序记录到 syslog 的最现代方式是啥?

java.util.logging jdk日志详解

如何从2行java.util.logging输出中抑制日期行? [重复]

Java日志介绍-java.util.logging.Logger