假设我有四个传统罐子:
“我的应用程序”和“我的其他应用程序”是不相关的应用程序,都有main()函数。他们都使用“my-library-app”中的各种库函数。这三个人都通过log4j进行日志记录(真的是slf4j,但我只是想让示例保持简单)。
目前,这两个应用程序设置了两个不同的log4j配置文件,这使得它们可以记录到两个不同的文件。
现在我想将所有内容转换为OSGi。所以我将前三个作为一个单独的包捆绑在一起,将实际应用程序的main()转换为Activators,然后捆绑或找到现有的log4j包。我在同一个OSGi框架中启动这两个应用程序。
但现在两个不同的应用程序不再登录到不同的文件!对?在JVM中只运行一个log4j实例,它从一个log4j.properties文件中获取其配置。
所以也许不是分别捆绑我的四个罐子,而是制作三个包装:
现在我可以为两个不同的应用程序获取不同的日志配置文件。但是我的图书馆的日志调用呢? My Library包将锁定到log4j的两个副本中的一个,现在从My Library生成的所有日志消息将在两个日志文件中的一个特定的一个中出现 - 比如说我的应用程序。但是,即使是来自My Library的来自我的其他应用程序的来自My Library的日志消息,也是如此!他们会转到错误的日志文件。
所以也许捆绑:
现在来自My Library的日志消息将转到他们自己的日志文件,我猜他们会比其中一些人使用错误的应用程序的日志文件更好,但是,它仍然不是很好。该文件具有来自两个应用程序的日志消息,并且两个用于任一应用程序的日志文件都没有来自这些应用程序的所有日志消息。
所以也许捆绑:
但是现在OSGi有什么意义呢?我不共享使用My Library或log4j。实际上它可能会更糟糕 - 我必须在我的所有实际应用程序包中粘贴多个副本,因为我希望看到他们的日志消息与导致它们的应用程序相关联。
所以也许备份并尝试不同的东西:我认为这不可能在log4j中,但在(比方说)slf4j我可以回到原始的捆绑计划:
然后我做了一些事情,比如把MDC信息放在每个线程中,说明线程来自哪个应用程序。对该MDC信息做出反应以确定它进入的日志文件。
但似乎这也行不通!从My App中的某个线程调用My Library中的某个函数可能会导致从My Library中生成一个新线程,该线程不一定与该MDC相关联。
更糟糕的是:我的图书馆可能有一些线程由任何使用我的图书馆的应用程序共享,因此无法与某些此类标记相关联。
所以,总而言之,我很难过。任何建议将不胜感激。提前谢谢。
答案 0 :(得分:3)
如果我理解正确的话:
我认为问题在于您将OSGi用作应用程序容器,就像隔离不同应用程序的servlet容器一样。您希望MyLibrary“属于”MyApp或MyOther应用程序。据我所知,你真的不希望这些应用程序共享任何内容,只是为了在单个JVM中运行良好。
这不是OSGi的真正构建,但我可以想到一些可能性:
新的OSGi规范 支持这个(称为子系统),但它是非常新的,可能对您的用例来说有点过于复杂,据我所知,没有实现然而。我现在不建议走这条路。
您可以复制捆绑包,如果您为它们指定了不同的符号名称,则可以使用Require-Bundle依赖于特定的捆绑包。然后我认为它应该有用,但坦率地说,我觉得它有点愚蠢。 OSGi然后没有添加任何东西,只是让事情复杂化,因为你最终会得到许多几乎相同的捆绑包。
您可以在一个JVM中启动两个OSGi实例,每个实例都有自己的一组包。这应该以一种优雅的方式将您的两个应用程序分开(Check Neil的回答here)。运行多个OSGi实例非常轻量级,您可以使用相同的包(在文件系统级别上),如果您执行想要共享代码,您可以将这些包添加到org.osgi.framework。 system.packages.extra属性。我认为这是你最好的选择。
最后,一些OSGi容器以专有方式支持它,如Eclipse Virgo和Apache Karaf。 (在处女座中称为“计划”,在Karaf中称为“实例”)。这可能值得一看,这实际上取决于你的情况。
希望它有所帮助,
谢
答案 1 :(得分:2)
执行此操作的最佳方法是从两个应用程序中删除日志记录设置(至少从您在OSGi中部署的jar中删除)。然后将pax日志记录添加到OSGi容器中。 Pax日志记录支持OSGi上的所有常见日志api。它可以配置一个log4j配置。在配置中,您可以设置log4j记录器和追加器以区分这两个应用程序。因此,您可以根据需要登录一个或两个文件。
您还可以将OSGi应用程序部署到已包含pax日志记录的Apache Karaf中。所以你不要自己设置它。
请参阅: http://team.ops4j.org/wiki/display/paxlogging/Pax+Logging
答案 2 :(得分:1)
这并不是特定于OSGi(正如Frank已经写过的那样)。
使用MDC通常是一种利用应用程序/运行时特定信息增强日志记录上下文的好方法。可能有机会使用MDC。一些MDC实现(SLF4J的BasicMDCAdapter
和LogbackMDCAdapter
)使用InheritableThreadLocal
。新线程从父线程继承MDC。但是,这需要使用您正在使用的实际实现进行验证。
另一种选择是在产生新线程时在库代码中复制/复制MDC。
第三种选择是允许应用程序代码将记录器注入库运行时。因此,库代码将使用由应用程序代码传递的记录器而不是每类记录器方法。