logging-log4j-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Ebersole, Steven" <steven.ebers...@vignette.com>
Subject RE: MDC in J2EE environment
Date Thu, 17 Apr 2003 21:14:53 GMT
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.

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.

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.

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.

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?

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
>     |>
>     |>----------------------------------------------------------
>     |-----------
>     |>To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
>     |>For additional commands, e-mail:
>     |log4j-user-help@jakarta.apache.org
>     |
>     |--
>     |Ceki
>     |
>     |
>     |-----------------------------------------------------------
>     |----------
>     |To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
>     |For additional commands, e-mail: log4j-user-help@jakarta.apache.org
>     |
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: log4j-user-help@jakarta.apache.org

--
Ceki 


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

---------------------------------------------------------------------
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