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]