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()?


    |-----Original Message-----
    |From: Ceki Gülcü [mailto:[EMAIL PROTECTED]
    |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
    |>
    |>----------------------------------------------------------
    |-----------
    |>To unsubscribe, e-mail: [EMAIL PROTECTED]
    |>For additional commands, e-mail: 
    |[EMAIL PROTECTED]
    |
    |--
    |Ceki 
    |
    |
    |-----------------------------------------------------------
    |----------
    |To unsubscribe, e-mail: [EMAIL PROTECTED]
    |For additional commands, e-mail: [EMAIL PROTECTED]
    |

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to