logging-log4j-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ceki Gülcü <c...@qos.ch>
Subject RE: MDC in J2EE environment
Date Mon, 21 Apr 2003 08:25:54 GMT
At 04:14 PM 4/17/2003 -0500, Ebersole, Steven wrote:
>I did got a working model of this approach set up, and it works well as long
>as every layer within that process space agrees on that contract and every
>thread process sets it up properly.

What does a thread need to set up? Also, in your code can make sure that 
you are referring to XMDC instead of MDC. For code that you do not control 
(nor can compile), the chances of referring to the same context key are 
quite low.

>Being the lazy person I am, I have been thinking of an easier, less
>error-prone approach.  In a nut shell, what I am attempting for the next
>version is to allow registering a "closure" with the MDC.  In my user
>example, this closure would simply look up the currently executing user.

That's quite an original idea. What would happen if the same user were 
logged in twice?

>However, I am uncertain of the best way to approach this.  One thought was
>to utilize the fact that ThreadLocalMap is an InheritableThreadLocal
>instance and try to set the closure on the parent.  That way each MDC would
>get a copy of the closure.  But I was uncertain how to accomplish this in a
>J2EE environment with its thread pool.

Can't you use the "if (value==null) then new ContextCounter" trick? See 
XMDC.put method.

>The other way would be to modify the MDC class to allow registration of a
>closure (or any global attribute).  This could then be kept statically on
>the MDC class.

Yep.

>I really like the first way because I would not need to modify any of the
>existing classes, but am uncertain how to implement it.  Any ideas?

Like you suggested in the previous paragraph. After modifying the MDC class 
to more or less match XMDC ckass, you would register a "closure" with the 
modified MDC class. The closure would be used instead of ContextCounter.

Basically, the idea is to let the user choose the counting method. (It's 
your idea actually. All I am doing is to rephrase it in my own words.)

>TIA
>
>
>
>-----Original Message-----
>From: Ceki Gülcü [mailto:ceki@qos.ch]
>Sent: Thursday, April 03, 2003 10:09 AM
>To: Log4J Users List
>Subject: RE: MDC in J2EE environment
>
>
>At 09:58 AM 4/3/2003 -0600, you wrote:
> >Actually just another thought occurred to me.  The MDC value is now a
> >ContextCounter instance instead of the actual value I put there.  The
> >default rendering is simply to call the Object's toString() correct?  So it
> >would seem that I would also need to add a renderer or override toString in
> >ContextCounter to call its context.toString()?
>
>You are right.
>
>public class ContextCounter {
>    int count = 0;
>    Object context;
>
>    public ContextCounter(Object c) { context = c; }
>
>    public void setContext(Object c) { context = c; }
>    public Object getContext() { return context; }
>
>    public boolean isCountZero() { return (count == 0); }
>    public void incCount() { count++; }
>    public void decCount() { count--; }
>
>    // We override toString so that Layouts print the correct information
>    public String toString() { return context.toString(); }
>}
>
>
> >     |-----Original Message-----
> >     |From: Ceki Gülcü [mailto:ceki@qos.ch]
> >     |Sent: Thursday, April 03, 2003 9:30 AM
> >     |To: Log4J Users List
> >     |Subject: Re: MDC in J2EE environment
> >     |
> >     |
> >     |Steven,
> >     |
> >     |Your question is quite intriguing.
> >     |
> >     |One solution would be to use some sort of counting. Thus,
> >     |each time you set
> >     |a key in the MDC you would increment the count of that key
> >     |in the MDC by
> >     |one. Each time you would "remove" the key you would
> >     |decrement the count by
> >     |one but not really remove (i.e. call MDC.remove). You
> >     |would really remove
> >     |only if the count reached zero (assuming the count started
> >     |at 0). I think
> >     |this provides for quite a solid solution.
> >     |
> >     |Let me give you an example:
> >     |
> >     |-- File XMDC.java ------------------------------------------
> >     |import org.apache.log4j.MDC;
> >     |
> >     |public class XMDC {
> >     |
> >     |   static Object get(String key) {
> >     |     return  MDC.get(key);
> >     |   }
> >     |
> >     |   static void put(String key, Object o) {
> >     |     Object value = MDC.get(key);
> >     |
> >     |     if(value == null) {
> >     |       ContextCounter cc = new ContextCounter(value);
> >     |       cc.incCount();
> >     |       MDC.put(key, cc);
> >     |     } else if(o instanceof ContextCounter) {
> >     |       ContextCounter cc = (ContextCounter) value;
> >     |       cc.incCount();
> >     |       cc.setContext(o);
> >     |     } else {
> >     |       MDC.put(key, o);
> >     |     }
> >     |   }
> >     |
> >     |   static void remove(String key) {
> >     |     Object o = MDC.get(key);
> >     |
> >     |     if(o == null) {
> >     |       ; // nothing to do because there is nothing there
> >     |     } else if(o instanceof ContextCounter) {
> >     |       ContextCounter cc = (ContextCounter) o;
> >     |       cc.decCount();
> >     |       if(cc.isCountZero()) {
> >     |         MDC.remove(key);
> >     |       }
> >     |     } else {
> >     |       MDC.remove(key);
> >     |     }
> >     |   }
> >     |}
> >     |
> >     |-- File  ContextCounter.java ---------------------------------
> >     |public class ContextCounter {
> >     |   int count = 0;
> >     |   Object context;
> >     |
> >     |   public ContextCounter(Object c) { context = c; }
> >     |
> >     |   public void setContext(Object c) { context = c; }
> >     |   public Object getContext() { return context; }
> >     |
> >     |   public boolean isCountZero() { return (count == 0); }
> >     |   public void incCount() { count++; }
> >     |   public void decCount() { count--; }
> >     |}
> >     |
> >     |In your code you would use XMDC which would automatically
> >     |track the
> >     |reference count of the keys and values you entered into
> >     |the MDC. Assuming
> >     |each XMDC.put operation is matched by the corresponding
> >     |XMDC.remove
> >     |operation, you are guaranteed that "inner" put operations
> >     |update the value
> >     |of the key while inner remove operation are inoffensive,
> >     |only the outer or
> >     |topmost XMDC.remove will remove the key and its value from the MDC.
> >     |
> >     |Think about it and let us know if it fits your purposes.
> >     |
> >     |At 08:13 AM 4/3/2003 -0600, Ebersole, Steven wrote:
> >     |>There is certain information which is thread contextual
> >     |which I would like
> >     |>to include into log4j's MDC to be available for logging.
> >     |One of these, for
> >     |>example, is the currently executing user.  My
> >     |architecture is such that all
> >     |>requests come through a layer of stateless session EJBs.
> >     |Now these EJBs can
> >     |>make calls into other session EJBs in order to fulfill
> >     |their use-case:
> >     |>
> >     |>public class SessionBeanA
> >     |>...
> >     |>{
> >     |>     ...
> >     |>     public void executeUseCase()
> >     |>     {
> >     |>         ... // Do some work
> >     |>         SessionBeanB sessionBeanB = ...; // Lookup SessionBeanB
> >     |>         sessionBeanB.executeSomeRelatedUseCase();
> >     |>         ... // Do some more work
> >     |>     }
> >     |>}
> >     |>
> >     |>public class SessionBeanB
> >     |>...
> >     |>{
> >     |>     ...
> >     |>     public void executeRelatedUseCase()
> >     |>     {
> >     |>         ... // Do something
> >     |>     }
> >     |>}
> >     |>
> >     |>The typical usage of MDC seems to be:
> >     |>1) put vars into MDC
> >     |>2) do your work
> >     |>3) clean up MDC
> >     |>
> >     |>But if I apply this usage to the scenario above, when
> >     |>SessionBeanB.executeRelatedUseCase() cleans up the MDC,
> >     |the information
> >     |>would no longer be contained in the MDC for LoggingEvents
> >     |generated within
> >     |>the "Do some more work" section of SessionBeanA.executeUseCase().
> >     |>
> >     |>I run weblogic 6.1, which unfortunately does not have
> >     |support for "call
> >     |>interceptors" to know when a user context has been bound
> >     |to a thread.
> >     |>Otherwise, I could simply setup MDC when a "session" is
> >     |begun and clean up
> >     |>the MDC when the session ends.  The only way around this
> >     |I have been able to
> >     |>think of is to just always call MDC.put( "USER",
> >     |>mySessionContext.getCallerPrincipal().getName() ) at the
> >     |beginning of each
> >     |>and every session bean method.  But I would not ever be
> >     |able to clean up the
> >     |>MDC because of this nesting described above.
> >     |>
> >     |>Is this OK?  Or this there a better way to do this?
> >     |>
> >     |>
> >     |>
> >     |>Steve Ebersole
> >     |>IT Integration Engineer
> >     |>Vignette Corporation
> >     |>Office: 512.741.4195
> >     |>Mobile: 512.297.5438
> >     |>
> >     |>Visit http://www.vignette.com

--
Ceki  For log4j documentation consider "The complete log4j manual"
       http://www.qos.ch/shop/products/clm_t.jsp 


---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org


Mime
View raw message