[slf4j-dev] MDC Type functionality

John E. Conlon jconlon at verticon.com
Tue Mar 27 20:39:09 CEST 2007


Paul,

Gardiner, Paul wrote:
> John,
>
> What you have in the repo looks like an implementation of an OSGi log
> service that uses SLF4j to do the logging.  What I have is a bit
> different.  I'll explain in a bit more detail.
>
> The OSGi log service I am using is the Equinox extended log service.
> The SLF4J implementation I did (the "log user") is a separate bundle
> that uses the OSGi log service; it doesn't provide any services itself.
> Instead, it writes out log entries to the OSGi log service.  I use the
> slf4j.api bundle, and then export org.slf4j.impl, and my logger package
> from my bundle, which the slf4j.api bundle then imports.  
>   


So your 'log user' might also be called in our slf4j naming conventions 
a: slf4j-osgi.
Bundle wiring (with the symbol --> meaning uses some package or service 
from another bundle) so far looks like:

originatingBundle(s) --> slf4j-api --> your 'log user'(aka slf4j-osgi) 

Right?
> Then I have a completely separate bundle (the "log reader user") that
> registers a listener with the OSGi log service.  Every time a log entry
> is made by the log user, the log reader user's filter method gets called
> (isLoggable), and if it returns true, its logged method gets called,
> which is where the logs get written out to their final destination.  
Paul, I have a rough idea of what your doing but I maybe hossed up 
somewhere -  if from the following you see that I am still confused 
please send me a list of the package imports and exports from each of 
your bundles and also note which services are used by each of the bundles.

> The
> logged method receives an ExtendedLogEntry object as its argument, which
> in addition to the stuff inherited from LogEntry, contains the logger
> name, thread id, a sequence number, and a context object, which can be
> any object defined by the log user.  Currently, I have the bundle and
> FQCN included in this object.  Note that the bundle is the bundle that
> made the original log entry, not the log user bundle.  My log reader
> bundle is using log4j to log out the messages.  
>
> So all together, there are three components - log user bundle (slf4j),
> the OSGi extended log service (in Equinox incubator), and the log reader
> user (currently I'm using log4j).  When making a log entry, the path the
> log message takes is ->originating bundle->log user->OSGi logger->log
> reader user.
>   
1. originatingBundle(s) --> 2. slf4j-api bundle--> 3. your 'log 
user'(aka slf4j-osgi) bundle --> 4. OSGi logger(LogService) bundle--> 5. 
'log reader user' bundle--> 6. log4j

I think I got it so far.  So how are you using the log4j(6)?  Or in 
other words how does your 'log reader user' bundle (5) use the log4j (6) 
packages, does it import them from a log4j bundle or are they privately 
packaged by you into your 'log reader user' (5) bundle?

> The advantage to this approach is that it is reasonably efficient,
> allows users to use LoggerFactory.getLogger(getClass())...  and still
> get bundle and other context information without having to use a service
> reference or bundle as an argument, it allows for different listener
> types, and it doesn't break existing OSGi log users/log reader users.
>   
Native LogService client bundles would then be wired like:
3*. LogService client bundles -->4. OSGi logger(LogService) bundle--> 5. 
'log reader user' bundle--> 6. log4j

Top end sounds good - both Equinox LogService clients (3*) and slf4j 
clients (1)  are supported. 
> So to answer your question about which implementation, the answer is
> it's an OSGi log user implementation.  
 OSGi logging (like many other OSGi services) can be split up (or 
combined) in many different ways.  So from slf4j perspective it's impl 
is your OSGi 'log user'(3) .  From the perspective of the actual 
outputing of log messages to the world the 'logging impl' would be 
log4j(6).  Sorry for mixing up terms in previous email.
> I implemented it using a
> LocationAwareLogger, but nothing is being done with the marker data at
> the moment, because I can't use logback as the log reader user.  
So your 'log user' (3) is implemented with a LocationAwareLogger which 
means you have the information you want at (3) and you want to 
(obliviously) get it to (6).

the path again...
3. 'log user'(aka slf4j-osgi) bundle --> 4. OSGi logger(LogService) 
bundle--> 5. 'log reader user' bundle--> 6. log4j

So if  you want your logging messages from originatingBundles that use 
slf4j apis to use this path
1. originatingBundle(s) --> 2. slf4j-api bundle--> 3. your 'log 
user'(aka slf4j-osgi) bundle --> 4. OSGi logger(LogService) bundle

and you want to retain context information then you would have to map 
the Marker information you have at 'log user' (3) to something that the 
LogService (4) can use passing that through to (5).  You would then have 
to pull out this information again at (5) and pass it to a logger(6) for 
output.   Sounds messy.

Why not implement the slf4j at  the 'log reader user' bundle (5)? 
>  The
> reason for this is that I already have a binding to OSGi, so if I then
> bind to logback, I have a classloader issue.  This should be ok if I
> completely segregate the bundles, but unfortunately I can't do that,
> because the Marker object comes from the log user bundle, which is
> different than the Marker object from the log reader user bundle.
>   
The Marker interface and the BasicMarker are exported from the slf4j-api 
bundle.
> Having said that, I'm not really asking for ideas on this, unless you
> have ideas off the top of your head.  I really haven't looked into this
> very much.  I tried implementing logback, it got lots of class loader
> errors, so I put log4j back.  
Your use case is rather generic so I expect this will come up again in 
the future so trying to get a handle on it now is a good thing.  
(Actually had it on my todo list to address this.) ;-)

Did you make a logback bundle?

Alternative suggestion -
An OSGi bundle implementation of a logback based slf4j binding that I 
will call here  'slf4j&osgireader-logback'  that also listens to the 
OSGi logService (5*).  That replaces the 'log reader user' bundle (5)  
the  log user (3) as well.

slf4j clients now do:
1. originatingBundle(s) --> 2. slf4j-api bundle--> 5*. 
slf4j&osgireader-logback bundle

and LogService clients now do:

3*. LogService client bundles -->4. OSGi logger(LogService) bundle--> 
5*.slf4j&osgireader-logback bundle

WDYT?
John

> Also, since both the log user and log
> reader user use SLF4J (since logback uses it), I end up getting an
> endless loop.  Once I have looked a bit deeper, I'll pose some
> questions, but for now, I just don't understand what's going on enough.
> I'm pretty sure the class loader issues are solvable though.
>
> As far as MDC goes, I think I'll just drop it.  I likely can get the job
> done with Markers, but I'll have to learn a bit more about how they
> work.  I understand how to use them, but need to learn how to use them
> properly and appropriately.
>
> Thanks,
> Paul
>
> -----Original Message-----
> From: dev-bounces at slf4j.org [mailto:dev-bounces at slf4j.org] On Behalf Of
> John E. Conlon
> Sent: Monday, March 26, 2007 5:26 PM
> To: slf4j developers list
> Subject: Re: [slf4j-dev] MDC Type functionality
>
> Gardiner, Paul wrote:
>   
>> The extended log service in equinox is similar to the standard one,
>>     
> but
>   
>> it adds a few extra methods for supporting named loggers, isLoggable,
>> and logging context objects.  Here's the basic idea:
>> https://www.eclipse.org/bugs/show_bug.cgi?id=147824.  It's just an
>> incubator project right now, but I have a pressing need at the moment.
>>   
>>     
>
> Interesting thread... I think our devs and users may find it most 
> interesting as slf4j is mentioned several times: :-)
>
> For example:
>
>   
>> Message payload for the LogService consistes primarily of String based
>>     
> messages
>   
>> and when relevant a Throwable. In some situations a generic
>>     
> String-based
>   
>> logging API is insufficient and in these cases it's desirable to pass
>>     
> additonal
>   
>> information with the understanding that it may be ignored. SLF4J uses
>>     
> it's
>   
>> Marker API in this fashion to allow strong coupling between logger and
>> recipient without impacting the generic log API.
>>     
>
> ...
>
>   
>> For this to work there are a couple of problems that need thought:
>> 1) we need a binding of the various logging API to the log service
>>  - we should consider looking at SLF4J as its defined a few useful
>>     
> static
>   
>> bindings already for JCL and log4j.
>>     
>
> ...
>
>   
>> I'm step by step migrating to SLF4J, because I really enjoy the
>>     
> simplicity and
>   
>> effectiveness of the API. Problem is: I NEED to know which OSGi Plugin
>>     
> is
>   
>> logging.  This is a serious problem, as all implementations only
>>     
> provide a
>   
>> thread based context.
>>     
> Note: The osgi-over-slf4j binding in the repo already provides this
> information as BundleSymbolicName and Version.
>
>
>
>
>
>   
>> I'm new to SLF4J, but I have looked around at markers, and found there
>> isn't a lot of info on how they are used.  
>>     
> Logger logger = LoggerFactory.getLogger("testMarker");
> Marker blue = MarkerFactory.getMarker("BLUE");
> logger.debug(blue, "hello");
> logger.info(blue, "hello");
> logger.warn(blue, "hello");
> logger.error(blue, "hello");
>
> Take a look at the test cases in slf4j.
>   
>> It looks like a single piece
>> of data, but with a hierarchy.  
>>     
> Yes.
>   
>> How would it work in this case?  Would I
>> (or the end user) create a marker named "session_id", and then create
>>     
> a
>   
>> child with the actual session id as the name?  
>>
>>   
>>     
> Well from what I gather about the Equinox extension is that there is a 
> context associated with logging messages.
> In your use case the user or client application is an Equinox Log 
> Service client, not a slf4j api user right? That would mean YOU would 
> have to create the Marker from the context in the log messages in your 
> 'equinox-over-slf4j'.
>
> Now the critical question is which Logging API implementation are you 
> planning to have your 'equinox-over-slf4j' bind with? If you use Markers
>
> you will have to use an implementation that uses them too and that would
>
> be either one that you implement or the Logback implementation. Check 
> the logback project for more details on how it handles marker 
> hierarchies. http://logback.qos.ch/
>
> cheers,
> John
>
>   
>> -----Original Message-----
>> From: dev-bounces at slf4j.org [mailto:dev-bounces at slf4j.org] On Behalf
>>     
> Of
>   
>> John E. Conlon
>> Sent: Monday, March 26, 2007 12:55 PM
>> To: slf4j developers list
>> Subject: Re: [slf4j-dev] MDC Type functionality
>>
>> Hello Paul,
>>
>> Have you considered using the
>>
>>
>>     org.slf4j.Marker
>>
>> to move this data to the readers? See the FAQ 
>> http://www.slf4j.org/faq.html#marker_interface
>>
>> BTW - You may have noticed in our slf4j source repository we have 
>> implemented a simple osgi log service for slf4j?
>> http://svn.slf4j.org/viewvc/slf4j/trunk/osgi-over-slf4j/
>>
>> I have not worked with the Equinox log service but plan to do so soon.
>>     
>
>   
>> Paul would you be so kind to please provide a link to the
>>     
> documentation 
>   
>> that can describe the Equinox extensions? Is this log service the same
>>     
>
>   
>> used by Eclipse as well?
>>
>> thanks,
>> John
>>
>>
>> Gardiner, Paul wrote:
>>   
>>     
>>> I have written an SLF4J binding to the Equinox extended log service, 
>>> which is an extension of the OSGi logging service, that includes 
>>> contextual information, and passes "isLoggable" statements through to
>>>       
>
>   
>>> log listeners (readers). The problem I have is supporting extra data 
>>> that is not part of the log message. SLF4J does not include MDC or
>>>       
> NDC
>   
>>>     
>>>       
>>   
>>     
>>> functionality, so I am not sure of the best way to pass through this 
>>> kind of data. A typical use case is session id, which is passed as 
>>> MDC. When the log entry is made, the session id is included in the 
>>> file appender, but omitted from an appender that sends pages. One 
>>> solution is to read all MDC data and pass it through to the OSGi log 
>>> service, and then recreate it in the log reader. However, I was 
>>> wondering if there was a more elegant/less expensive solution.
>>>
>>> Thanks,
>>>
>>> Paul
>>>
>>>
>>>     
>>>       
> ------------------------------------------------------------------------
>   
>>   
>>     
>>> _______________________________________________
>>> dev mailing list
>>> dev at slf4j.org
>>> http://www.slf4j.org/mailman/listinfo/dev
>>>     
>>>       
>> _______________________________________________
>> dev mailing list
>> dev at slf4j.org
>> http://www.slf4j.org/mailman/listinfo/dev
>> _______________________________________________
>> dev mailing list
>> dev at slf4j.org
>> http://www.slf4j.org/mailman/listinfo/dev
>>
>>
>>   
>>     
>
> _______________________________________________
> dev mailing list
> dev at slf4j.org
> http://www.slf4j.org/mailman/listinfo/dev
> _______________________________________________
> dev mailing list
> dev at slf4j.org
> http://www.slf4j.org/mailman/listinfo/dev
>
>
>   




More information about the slf4j-dev mailing list