Reputation: 1
Let's say I have four legacy jars:
"My App" and "My Other App" are unrelated applications, both with main() functions. They both use various library functions from "my-library-app". All three do logging through log4j (really slf4j, but I just want to keep the example simple).
Currently, the two applications are set up with two different log4j config files, which cause them to log to two different files.
Now I want to convert everything to OSGi. So I bundle up the first three each as a separate bundle, convert the main() of the actual apps to Activators, and either bundle up or find an existing bundle of log4j. I start both apps in the same OSGi framework.
But now the two distinct apps no longer log to different files! Right? There's only one instance of log4j running in the JVM, and it gets its configuration out of one single log4j.properties file.
So maybe instead of bundling each of my four jars separately, I make three bundles:
Now I can get different logging config files for the two different apps. But what about log calls from My Library? The My Library bundle will latch onto one of the two copies of log4j, and now all log messages produced from My Library will come out in one specific one of the two log files - let's say the one for My App. But that's true even if it's a log message from My Library due to a call from My Other App! They'll go to the wrong log file.
So maybe bundle:
Now the log messages from My Library are going to their own log file, which I guess is better than some of them going to the wrong app's log file, but still, it's not great. That file has log messages from both apps, and neither of the log files intended to be for either app have all log messages from those apps.
So maybe bundle:
But now what's the point of OSGi? I'm not sharing use of My Library or of log4j. And in reality it will likely be even worse - there will be a bunch of jars that I have to stick multiple copies of into all of my actual app bundles, simply because I want to see their log messages associated with the app that caused them.
So maybe back up and try something different: I don't think this is possible in log4j, but in (say) slf4j I could go back to the original bundle plan:
And then I do something like put MDC information in each thread saying what app the thread is from. React to that MDC info to determine what log file it goes into.
But it seems like that won't work either! A call from some thread in My App to some function in My Library could cause a new thread to be spawned from My Library, which would not necessarily be associated with that MDC.
And it's worse than that: My Library could have some thread that is shared by any app that uses My Library, so cannot possibly be associated with some such marker.
So, all in all, I'm stumped. Any suggestions would be greatly appreciated. Thanks in advance.
Upvotes: 0
Views: 994
Reputation: 2359
This isn't really specific to OSGi (as Frank already wrote).
Using the MDC is generally a good approach to enhance the logging context with application/runtime specific information. There may be a chance to use the MDC. Some MDC implementations (SLF4J's BasicMDCAdapter
and LogbackMDCAdapter
) use an InheritableThreadLocal
. New threads inherit the MDC from a parent thread. However, this needs to be verified with the actual implementation you are using.
Another option is to copy/duplicate the MDC in your library code when you are spawning new threads.
A third option is to allow application code to inject a logger into the library runtime. Thus, the library code would then use a logger passed by the application code instead of a per class logger approach.
Upvotes: 1
Reputation: 19606
The best way to do this is to remove the logging setup from both applications (at least from the jars you deploy in OSGi). Then you add pax logging to your OSGi container. Pax logging supports all common log apis on OSGi. It can be configured with one log4j config. In the config you can set up log4j loggers and appenders to distinguish between the two applications. So you can log into one or two files just as you like.
You can also deploy your OSGi apps into Apache Karaf which already includes pax logging. So you do not haave to set it up yourself.
See: http://team.ops4j.org/wiki/display/paxlogging/Pax+Logging
Upvotes: 2
Reputation: 2748
If I understand you correctly:
I think the problem is is that you use OSGi as a application container, like a servlet container which will isolate different applications. You want MyLibrary to 'belong' to either MyApp or MyOther app. As far as I can see, you really don't want these applications to share anything, just to play nice inside a single JVM.
This is not really what OSGi was built for, but I can think of a few possibilities:
The new OSGi specification does support this (called subsystems) but it is very new, probably a bit too complicated for your use case, and as far as I know there is no implementation yet. I don't recommend to walk this path for now.
You can duplicate bundles, and if you give them a different symbolic name, you could depend on specific bundles, using Require-Bundle. Then I think it should work, but frankly I think it is a bit stupid. OSGi then adds nothing and just complicates stuff, as you'll end up with lots of nearly identical bundles.
You could start two OSGi instances in a single JVM, each with their own set of bundles. That should separate your two applications in a sort of elegant way (Check Neil's answer here). Running multiple OSGi instances is pretty light weight, you can use the same bundles (on file system level), and if you do want to share code you can add those packages to the org.osgi.framework.system.packages.extra property. I think this is your best bet.
Finally, some OSGi containers support this in a proprietary way, like Eclipse Virgo and Apache Karaf. (Called 'plans' in Virgo and 'instances' in Karaf). It might be worth a look, it really depends on your situation.
Hope it helps,
Frank
Upvotes: 3