【问题标题】:OSGi logging from legacy apps?从遗留应用程序进行 OSGi 日志记录?
【发布时间】:2012-08-04 20:47:24
【问题描述】:

假设我有四个遗留 jar:

  1. my-library.jar
  2. my-app.jar
  3. my-other-app.jar
  4. log4j.jar

“我的应用程序”和“我的其他应用程序”是不相关的应用程序,都具有 main() 函数。他们都使用“my-library-app”中的各种库函数。这三个都通过 log4j 进行日志记录(真的是 slf4j,但我只是想让示例保持简单)。

目前,这两个应用程序设置了两个不同的 log4j 配置文件,这导致它们登录到两个不同的文件。

现在我想将所有内容都转换为 OSGi。因此,我将前三个分别捆绑为一个单独的捆绑包,将实际应用程序的 main() 转换为 Activators,然后捆绑或找到现有的 log4j 捆绑包。我在同一个 OSGi 框架中启动这两个应用程序。

但现在这两个不同的应用程序不再登录到不同的文件!正确的? JVM 中只有一个 log4j 实例在运行,它从一个 log4j.properties 文件中获取配置。

所以也许我没有分别捆绑我的四个罐子,而是做了三个捆绑:

  1. 我的图书馆
  2. 我的应用程序加 log4j
  3. 我的其他应用程序加 log4j

现在我可以为两个不同的应用程序获取不同的日志记录配置文件。但是来自我的图书馆的日志调用呢? My Library 捆绑包将锁定到 log4j 的两个副本之一,现在从 My Library 生成的所有日志消息都将出现在两个日志文件中的一个特定文件中 - 比如说我的应用程序中的那个。但即使它是我的图书馆由于来自我的其他应用程序的调用而发出的日志消息也是如此!他们会转到错误的日志文件。

所以也许捆绑:

  1. 我的图书馆加 log4j
  2. 我的应用程序加 log4j
  3. 我的其他应用程序加 log4j

现在“我的库”中的日志消息将转到它们自己的日志文件,我想这比其中一些转到错误应用程序的日志文件要好,但仍然不是很好。该文件包含来自两个应用程序的日志消息,并且打算用于任一应用程序的日志文件都没有来自这些应用程序的所有日志消息。

所以也许捆绑:

  1. 我的应用程序加我​​的库加 log4j
  2. 我的其他应用程序加我​​的图书馆加 log4j

但是现在 OSGi 的意义何在?我没有分享我的图书馆或 log4j 的使用。实际上,情况可能会更糟——我必须将一堆 jar 包粘贴到我所有的实际应用程序包中,这仅仅是因为我想查看它们的日志消息与导致它们的应用程序相关联。

所以也许备份并尝试不同的东西:我认为这在 log4j 中是不可能的,但在(比如说)slf4j 中我可以回到原来的捆绑计划:

  1. 我的图书馆
  2. 我的应用程序
  3. 我的其他应用
  4. log4j

然后我会在每个线程中添加 MDC 信息,说明线程来自哪个应用程序。对该 MDC 信息做出反应以确定它进入哪个日志文件。

但这似乎也行不通!从“我的应用”中的某个线程调用“我的库”中的某个函数可能会导致从“我的库”中生成一个新线程,该线程不一定与该 MDC 相关联。

比这更糟糕的是:我的图书馆可能有一些线程被任何使用我的图书馆的应用程序共享,所以不可能与一些这样的标记相关联。

所以,总而言之,我被难住了。任何建议将不胜感激。提前致谢。

【问题讨论】:

标签: logging log4j osgi slf4j legacy


【解决方案1】:

如果我理解正确的话:

  • 您曾经有两个完全独立的应用程序,在不同的 JVM 中运行。他们确实共享了一个库,但仅在文件系统级别,应用程序彼此不知道。
  • 现在您使用一个 JVM,并且应用程序相互干扰(目前是 log4j,但可能还有其他问题),您想使用 OSGi 来解决这个问题。

我认为问题在于您使用 OSGi 作为应用程序容器,就像一个 servlet 容器,它将隔离不同的应用程序。您希望 MyLibrary “属于” MyApp 或 MyOther 应用程序。据我所知,您真的不希望这些应用程序共享任何东西,只是为了在单个 JVM 中运行良好。

这并不是 OSGi 的真正目的,但我可以想到一些可能性:

  • 新的 OSGi 规范确实支持这个(称为子系统),但它非常新,对于您的用例来说可能有点过于复杂,据我所知没有实现然而。我暂时不建议走这条路。

  • 您可以复制包,如果您给它们一个不同的符号名称,您可以使用 Require-Bundle 依赖于特定的包。然后我认为它应该工作,但坦率地说我认为它有点愚蠢。然后,OSGi 什么都不添加,只会使事情复杂化,因为您最终会得到许多几乎相同的包。

  • 您可以在单个 JVM 中启动两个 OSGi 实例,每个实例都有自己的捆绑包集。这应该以一种优雅的方式将您的两个应用程序分开(检查 Neil 的回答 here)。运行多个 OSGi 实例的重量非常轻,您可以使用相同的包(在文件系统级别),如果您确实想要共享代码,您可以将这些包添加到 org.osgi.framework。 system.packages.extra 属性。我认为这是你最好的选择。

  • 最后,一些 OSGi 容器以专有方式支持这一点,例如 Eclipse Virgo 和 Apache Karaf。 (在处女座称为“计划”,在Karaf 称为“实例”)。可能值得一看,这真的取决于你的情况。

希望对你有帮助,

弗兰克

【讨论】:

    【解决方案2】:

    执行此操作的最佳方法是从两个应用程序中删除日志记录设置(至少从您在 OSGi 中部署的 jars 中删除)。然后将 pax 日志添加到您的 OSGi 容器。 Pax 日志支持 OSGi 上所有常见的日志 API。它可以配置一个 log4j 配置。在配置中,您可以设置 log4j 记录器和附加器来区分这两个应用程序。所以你可以随心所欲地登录一两个文件。

    您还可以将您的 OSGi 应用程序部署到已包含 pax 日志记录的 Apache Karaf 中。所以你不必自己设置。

    见: http://team.ops4j.org/wiki/display/paxlogging/Pax+Logging

    http://karaf.apache.org/

    【讨论】:

      【解决方案3】:

      这并不是真正特定于 OSGi(正如 Frank 已经写过的)。

      使用 MDC 通常是使用应用程序/运行时特定信息增强日志记录上下文的好方法。可能有机会使用 MDC。一些 MDC 实现(SLF4J 的BasicMDCAdapterLogbackMDCAdapter)使用InheritableThreadLocal。新线程从父线程继承 MDC。但是,这需要通过您正在使用的实际实现进行验证。

      另一种选择是在生成新线程时复制/复制库代码中的 MDC。

      第三种选择是允许应用程序代码将记录器注入库运行时。因此,库代码将使用应用程序代码传递的记录器,而不是按类记录器方法。

      【讨论】:

        猜你喜欢
        • 2012-07-20
        • 2016-01-14
        • 1970-01-01
        • 1970-01-01
        • 2017-04-09
        • 2021-03-22
        • 1970-01-01
        • 2021-03-09
        • 1970-01-01
        相关资源
        最近更新 更多