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]