【问题标题】:How to send java.util.logging to log4j?如何将 java.util.logging 发送到 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 日志记录会引起如此头痛。

【问题讨论】:

标签: java logging log4j apache-commons slf4j


【解决方案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>
      

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

      1. svn cohttp://svn.apache.org/repos/asf/logging/sandbox/jul-to-log4j-bridge/
      2. 编辑 pom.xml,将 log4j:log4j:1.2.15 的依赖替换为 log4j:apache-log4j-extras:1.2.17 并删除对 apache-log4j-component 的依赖
      3. 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

      【讨论】:

        猜你喜欢
        • 2014-03-13
        • 2017-10-20
        • 2017-05-26
        • 2011-05-19
        • 1970-01-01
        • 2019-08-27
        • 2018-10-31
        • 2011-05-29
        • 2015-10-02
        相关资源
        最近更新 更多