I'm working on a utility program that is similar to Test.java (included inline).
There's several "process" methods. A higher level process method calls a lower
level process method, and that method may in turn call an even lower level
process method. These levels could be anything (major/minor/micro,
directory/subdirectory/subdirectory/..., Company/Department/Employee, ...) These
methods can also be "jumped into" at any level, meaning I could start at, say,
the major level, or I could start at major level 4, minor level 2, and process
all the micro levels. I could also process multiple things, "jumping in" at
various levels, successively.
All of this is to set up my reasoning for creating "MDCStack".

I wanted to use MDC to track my context. I started with not clearing the MDC,
and had output similar to case 1-- not clearing MDC...
      ...
      [foo/bar/baz] | ...finished processing level 3
      [foo/bar/baz] | processing all levels...
      [A/bar/baz] | processing level 1...
      [A/1/baz] | processing level 2...
      [A/1/x] | processing level 3...
      ...
      [C/3/z] | ...finished processing level 3
      [C/3/z] | ...finished processing level 2
      [C/3/z] | ...finished processing level 1
      [C/3/z] | ...finished processing all levels
      ...
For the most part, this didn't really give me the correct "diagnostic context" I
was looking for-- too much unnecesary info was left in the MDC.

So, I figured, I should clear the MDC at the correct places, as in case 2--
clearing entire MDC...
      ...
      [foo/bar/baz] | ...finished processing level 3
      [//] | processing all levels...
      [A//] | processing level 1...
      [A/1/] | processing level 2...
      [A/1/x] | processing level 3...
      ...
      [C/3/z] | ...finished processing level 3
      [//] | ...finished processing level 2
      [//] | ...finished processing level 1
      [//] | ...finished processing all levels
      ...
This worked in some cases, but in some cases, the diagnostic context was lost,
because MDC.remove() was called too many times.

So, if the MDC.remove() was called too many times, maybe I should just remove
the "last" level, as in case 3-- clearing only last level from MDC...
      ...
      [foo/bar/baz] | ...finished processing level 3
      [foo/bar/] | processing all levels...
      [A/bar/] | processing level 1...
      [A/1/] | processing level 2...
      [A/1/x] | processing level 3...
      ...
      [C/3/z] | ...finished processing level 3
      [C/3/] | ...finished processing level 2
      [C//] | ...finished processing level 1
      [//] | ...finished processing all levels
      ...
This also worked in some cases, but in not in others.

So I created MDCStack.java (included inline). This finally gave me the output I
wanted-- case 4-- using MDCStack...
      ...
      [foo/bar/baz] | ...finished processing level 3
      [//] | processing all levels...
      [A//] | processing level 1...
      [A/1/] | processing level 2...
      [A/1/x] | processing level 3...
      ...
      [C/3/z] | ...finished processing level 3
      [C/3/] | ...finished processing level 2
      [C//] | ...finished processing level 1
      [//] | ...finished processing all levels
      ...
This, to me, is the correct "diagnostic context".

Why didn't I just use NDC? I like MDC better, and it has much more flexibility
in the ways you can write the output, using PatternLayout.
I didn't see anything similar to this in searching through the mailing list
archives.
I offer this as is. If you can use it, or improve on it, please do. I'm sure
it's not perfect, but it's helped me out a lot.
If there's anything wrong or that can be improved in my design or analysis,
please comment.

Mitchell Ackermann

//-----------------------------------------------------------------------------
// MDCStack.java

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.apache.log4j.MDC;

public class MDCStack
{
     protected static Map map = new HashMap();

     protected MDCStack() {}

     public static synchronized void push(String key, Object value)
     {
         Stack stack = null;
         if (map.containsKey(key))
         {
             stack = (Stack)(map.get(key));
         }

         if (stack == null)
         {
             stack = new Stack();
             map.put(key, stack);
         }

         stack.push(value);
         MDC.put(key, value);
     }

     public static synchronized void pop(String key)
     {
         Stack stack = null;
         if (map.containsKey(key))
         {
             stack = (Stack)(map.get(key));
         }

         if ((stack == null) || (stack.empty()))
         {
             MDC.remove(key);
         }
         else
         {
             Object o = stack.pop();

             if (stack.empty())
             {
                 MDC.remove(key);
             }
             else
             {
                 MDC.put(key, o);
             }
         }
     }
}

//-----------------------------------------------------------------------------
// Test.java

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.log4j.PatternLayout;

class Test
{
     static final Logger logger = Logger.getRootLogger();

     boolean useStack;
     boolean clearOnlyLastLevelFromMDC;
     boolean clearEntireMDC;

     void process()
     {
         logger.info("processing all levels...");

         process("A");
         process("B");
         process("C");

         logger.info("...finished processing all levels");
     }
     void process(String level1)
     {
         if (useStack)
         {
             MDCStack.push("l1", level1);
         }
         else
         {
             MDC.put("l1", level1);
         }
         logger.info("processing level 1...");

         process(level1, "1");
         process(level1, "2");
         process(level1, "3");

         logger.info("...finished processing level 1");
         if (useStack)
         {
             MDCStack.pop("l1");
         }
         else if (clearEntireMDC || clearOnlyLastLevelFromMDC)
         {
             MDC.remove("l1");
         }
     }
     void process(String level1, String level2)
     {
         if (useStack)
         {
             MDCStack.push("l1", level1);
             MDCStack.push("l2", level2);
         }
         else
         {
             MDC.put("l1", level1);
             MDC.put("l2", level2);
         }
         logger.info("processing level 2...");

         process(level1, level2, "x");
         process(level1, level2, "y");
         process(level1, level2, "z");

         logger.info("...finished processing level 2");
         if (useStack)
         {
             MDCStack.pop("l2");
             MDCStack.pop("l1");
         }
         else if (clearEntireMDC)
         {
             MDC.remove("l2");
             MDC.remove("l1");
         }
         else if (clearOnlyLastLevelFromMDC)
         {
             MDC.remove("l2");
         }
     }
     void process(String level1, String level2, String level3)
     {
         if (useStack)
         {
             MDCStack.push("l1", level1);
             MDCStack.push("l2", level2);
             MDCStack.push("l3", level3);
         }
         else
         {
             MDC.put("l1", level1);
             MDC.put("l2", level2);
             MDC.put("l3", level3);
         }
         logger.info("processing level 3...");

         //logger.info("--- doing some major work now ---");

         logger.info("...finished processing level 3");
         if (useStack)
         {
             MDCStack.pop("l3");
             MDCStack.pop("l2");
             MDCStack.pop("l1");
         }
         else if (clearEntireMDC)
         {
             MDC.remove("l3");
             MDC.remove("l2");
             MDC.remove("l1");
         }
         else if (clearOnlyLastLevelFromMDC)
         {
             MDC.remove("l3");
         }
     }

     public static void main(String[] s)
     {
         Layout layout = new PatternLayout("[%X{l1}/%X{l2}/%X{l3}] | %m%n");
         logger.addAppender(new ConsoleAppender(layout));

         Test t = new Test();

         t.useStack = false;
         t.clearEntireMDC = false;
         t.clearOnlyLastLevelFromMDC = false;
         logger.info("beginning case 1-- not clearing MDC...");
         t.process("foo", "bar", "baz");
         t.process();
         logger.info("...finished case 1-- not clearing MDC");
         System.out.println();

         // this is only here for demo-ing; I wouldn't do this in an actual program
         MDC.remove("l1");
         MDC.remove("l2");
         MDC.remove("l3");

         t.clearEntireMDC = true;
         t.clearOnlyLastLevelFromMDC = false;
         logger.info("beginning case 2-- clearing entire MDC...");
         t.process("foo", "bar", "baz");
         t.process();
         logger.info("...finished case 2-- clearing entire MDC");
         System.out.println();

         // ...
         MDC.remove("l1");
         MDC.remove("l2");
         MDC.remove("l3");

         t.clearEntireMDC = false;
         t.clearOnlyLastLevelFromMDC = true;
         logger.info("beginning case 3-- clearing only last level from MDC...");
         t.process("foo", "bar", "baz");
         t.process();
         logger.info("...finished case 3-- clearing only last level from MDC...");
         System.out.println();

         // ...
         MDC.remove("l1");
         MDC.remove("l2");
         MDC.remove("l3");

         t.useStack = true;
         logger.info("beginning case 4-- using MDCStack...");
         t.process("foo", "bar", "baz");
         t.process();
         logger.info("...finished case 4-- using MDCStack");
     }
}

//-----------------------------------------------------------------------------
// all output from Test
[//] | beginning case 1-- not clearing MDC...
[foo/bar/baz] | processing level 3...
[foo/bar/baz] | ...finished processing level 3
[foo/bar/baz] | processing all levels...
[A/bar/baz] | processing level 1...
[A/1/baz] | processing level 2...
[A/1/x] | processing level 3...
[A/1/x] | ...finished processing level 3
[A/1/y] | processing level 3...
[A/1/y] | ...finished processing level 3
[A/1/z] | processing level 3...
[A/1/z] | ...finished processing level 3
[A/1/z] | ...finished processing level 2
[A/2/z] | processing level 2...
[A/2/x] | processing level 3...
[A/2/x] | ...finished processing level 3
[A/2/y] | processing level 3...
[A/2/y] | ...finished processing level 3
[A/2/z] | processing level 3...
[A/2/z] | ...finished processing level 3
[A/2/z] | ...finished processing level 2
[A/3/z] | processing level 2...
[A/3/x] | processing level 3...
[A/3/x] | ...finished processing level 3
[A/3/y] | processing level 3...
[A/3/y] | ...finished processing level 3
[A/3/z] | processing level 3...
[A/3/z] | ...finished processing level 3
[A/3/z] | ...finished processing level 2
[A/3/z] | ...finished processing level 1
[B/3/z] | processing level 1...
[B/1/z] | processing level 2...
[B/1/x] | processing level 3...
[B/1/x] | ...finished processing level 3
[B/1/y] | processing level 3...
[B/1/y] | ...finished processing level 3
[B/1/z] | processing level 3...
[B/1/z] | ...finished processing level 3
[B/1/z] | ...finished processing level 2
[B/2/z] | processing level 2...
[B/2/x] | processing level 3...
[B/2/x] | ...finished processing level 3
[B/2/y] | processing level 3...
[B/2/y] | ...finished processing level 3
[B/2/z] | processing level 3...
[B/2/z] | ...finished processing level 3
[B/2/z] | ...finished processing level 2
[B/3/z] | processing level 2...
[B/3/x] | processing level 3...
[B/3/x] | ...finished processing level 3
[B/3/y] | processing level 3...
[B/3/y] | ...finished processing level 3
[B/3/z] | processing level 3...
[B/3/z] | ...finished processing level 3
[B/3/z] | ...finished processing level 2
[B/3/z] | ...finished processing level 1
[C/3/z] | processing level 1...
[C/1/z] | processing level 2...
[C/1/x] | processing level 3...
[C/1/x] | ...finished processing level 3
[C/1/y] | processing level 3...
[C/1/y] | ...finished processing level 3
[C/1/z] | processing level 3...
[C/1/z] | ...finished processing level 3
[C/1/z] | ...finished processing level 2
[C/2/z] | processing level 2...
[C/2/x] | processing level 3...
[C/2/x] | ...finished processing level 3
[C/2/y] | processing level 3...
[C/2/y] | ...finished processing level 3
[C/2/z] | processing level 3...
[C/2/z] | ...finished processing level 3
[C/2/z] | ...finished processing level 2
[C/3/z] | processing level 2...
[C/3/x] | processing level 3...
[C/3/x] | ...finished processing level 3
[C/3/y] | processing level 3...
[C/3/y] | ...finished processing level 3
[C/3/z] | processing level 3...
[C/3/z] | ...finished processing level 3
[C/3/z] | ...finished processing level 2
[C/3/z] | ...finished processing level 1
[C/3/z] | ...finished processing all levels
[C/3/z] | ...finished case 1-- not clearing MDC

[//] | beginning case 2-- clearing entire MDC...
[foo/bar/baz] | processing level 3...
[foo/bar/baz] | ...finished processing level 3
[//] | processing all levels...
[A//] | processing level 1...
[A/1/] | processing level 2...
[A/1/x] | processing level 3...
[A/1/x] | ...finished processing level 3
[A/1/y] | processing level 3...
[A/1/y] | ...finished processing level 3
[A/1/z] | processing level 3...
[A/1/z] | ...finished processing level 3
[//] | ...finished processing level 2
[A/2/] | processing level 2...
[A/2/x] | processing level 3...
[A/2/x] | ...finished processing level 3
[A/2/y] | processing level 3...
[A/2/y] | ...finished processing level 3
[A/2/z] | processing level 3...
[A/2/z] | ...finished processing level 3
[//] | ...finished processing level 2
[A/3/] | processing level 2...
[A/3/x] | processing level 3...
[A/3/x] | ...finished processing level 3
[A/3/y] | processing level 3...
[A/3/y] | ...finished processing level 3
[A/3/z] | processing level 3...
[A/3/z] | ...finished processing level 3
[//] | ...finished processing level 2
[//] | ...finished processing level 1
[B//] | processing level 1...
[B/1/] | processing level 2...
[B/1/x] | processing level 3...
[B/1/x] | ...finished processing level 3
[B/1/y] | processing level 3...
[B/1/y] | ...finished processing level 3
[B/1/z] | processing level 3...
[B/1/z] | ...finished processing level 3
[//] | ...finished processing level 2
[B/2/] | processing level 2...
[B/2/x] | processing level 3...
[B/2/x] | ...finished processing level 3
[B/2/y] | processing level 3...
[B/2/y] | ...finished processing level 3
[B/2/z] | processing level 3...
[B/2/z] | ...finished processing level 3
[//] | ...finished processing level 2
[B/3/] | processing level 2...
[B/3/x] | processing level 3...
[B/3/x] | ...finished processing level 3
[B/3/y] | processing level 3...
[B/3/y] | ...finished processing level 3
[B/3/z] | processing level 3...
[B/3/z] | ...finished processing level 3
[//] | ...finished processing level 2
[//] | ...finished processing level 1
[C//] | processing level 1...
[C/1/] | processing level 2...
[C/1/x] | processing level 3...
[C/1/x] | ...finished processing level 3
[C/1/y] | processing level 3...
[C/1/y] | ...finished processing level 3
[C/1/z] | processing level 3...
[C/1/z] | ...finished processing level 3
[//] | ...finished processing level 2
[C/2/] | processing level 2...
[C/2/x] | processing level 3...
[C/2/x] | ...finished processing level 3
[C/2/y] | processing level 3...
[C/2/y] | ...finished processing level 3
[C/2/z] | processing level 3...
[C/2/z] | ...finished processing level 3
[//] | ...finished processing level 2
[C/3/] | processing level 2...
[C/3/x] | processing level 3...
[C/3/x] | ...finished processing level 3
[C/3/y] | processing level 3...
[C/3/y] | ...finished processing level 3
[C/3/z] | processing level 3...
[C/3/z] | ...finished processing level 3
[//] | ...finished processing level 2
[//] | ...finished processing level 1
[//] | ...finished processing all levels
[//] | ...finished case 2-- clearing entire MDC

[//] | beginning case 3-- clearing only last level from MDC...
[foo/bar/baz] | processing level 3...
[foo/bar/baz] | ...finished processing level 3
[foo/bar/] | processing all levels...
[A/bar/] | processing level 1...
[A/1/] | processing level 2...
[A/1/x] | processing level 3...
[A/1/x] | ...finished processing level 3
[A/1/y] | processing level 3...
[A/1/y] | ...finished processing level 3
[A/1/z] | processing level 3...
[A/1/z] | ...finished processing level 3
[A/1/] | ...finished processing level 2
[A/2/] | processing level 2...
[A/2/x] | processing level 3...
[A/2/x] | ...finished processing level 3
[A/2/y] | processing level 3...
[A/2/y] | ...finished processing level 3
[A/2/z] | processing level 3...
[A/2/z] | ...finished processing level 3
[A/2/] | ...finished processing level 2
[A/3/] | processing level 2...
[A/3/x] | processing level 3...
[A/3/x] | ...finished processing level 3
[A/3/y] | processing level 3...
[A/3/y] | ...finished processing level 3
[A/3/z] | processing level 3...
[A/3/z] | ...finished processing level 3
[A/3/] | ...finished processing level 2
[A//] | ...finished processing level 1
[B//] | processing level 1...
[B/1/] | processing level 2...
[B/1/x] | processing level 3...
[B/1/x] | ...finished processing level 3
[B/1/y] | processing level 3...
[B/1/y] | ...finished processing level 3
[B/1/z] | processing level 3...
[B/1/z] | ...finished processing level 3
[B/1/] | ...finished processing level 2
[B/2/] | processing level 2...
[B/2/x] | processing level 3...
[B/2/x] | ...finished processing level 3
[B/2/y] | processing level 3...
[B/2/y] | ...finished processing level 3
[B/2/z] | processing level 3...
[B/2/z] | ...finished processing level 3
[B/2/] | ...finished processing level 2
[B/3/] | processing level 2...
[B/3/x] | processing level 3...
[B/3/x] | ...finished processing level 3
[B/3/y] | processing level 3...
[B/3/y] | ...finished processing level 3
[B/3/z] | processing level 3...
[B/3/z] | ...finished processing level 3
[B/3/] | ...finished processing level 2
[B//] | ...finished processing level 1
[C//] | processing level 1...
[C/1/] | processing level 2...
[C/1/x] | processing level 3...
[C/1/x] | ...finished processing level 3
[C/1/y] | processing level 3...
[C/1/y] | ...finished processing level 3
[C/1/z] | processing level 3...
[C/1/z] | ...finished processing level 3
[C/1/] | ...finished processing level 2
[C/2/] | processing level 2...
[C/2/x] | processing level 3...
[C/2/x] | ...finished processing level 3
[C/2/y] | processing level 3...
[C/2/y] | ...finished processing level 3
[C/2/z] | processing level 3...
[C/2/z] | ...finished processing level 3
[C/2/] | ...finished processing level 2
[C/3/] | processing level 2...
[C/3/x] | processing level 3...
[C/3/x] | ...finished processing level 3
[C/3/y] | processing level 3...
[C/3/y] | ...finished processing level 3
[C/3/z] | processing level 3...
[C/3/z] | ...finished processing level 3
[C/3/] | ...finished processing level 2
[C//] | ...finished processing level 1
[//] | ...finished processing all levels
[//] | ...finished case 3-- clearing only last level from MDC...

[//] | beginning case 4-- using MDCStack...
[foo/bar/baz] | processing level 3...
[foo/bar/baz] | ...finished processing level 3
[//] | processing all levels...
[A//] | processing level 1...
[A/1/] | processing level 2...
[A/1/x] | processing level 3...
[A/1/x] | ...finished processing level 3
[A/1/y] | processing level 3...
[A/1/y] | ...finished processing level 3
[A/1/z] | processing level 3...
[A/1/z] | ...finished processing level 3
[A/1/] | ...finished processing level 2
[A/2/] | processing level 2...
[A/2/x] | processing level 3...
[A/2/x] | ...finished processing level 3
[A/2/y] | processing level 3...
[A/2/y] | ...finished processing level 3
[A/2/z] | processing level 3...
[A/2/z] | ...finished processing level 3
[A/2/] | ...finished processing level 2
[A/3/] | processing level 2...
[A/3/x] | processing level 3...
[A/3/x] | ...finished processing level 3
[A/3/y] | processing level 3...
[A/3/y] | ...finished processing level 3
[A/3/z] | processing level 3...
[A/3/z] | ...finished processing level 3
[A/3/] | ...finished processing level 2
[A//] | ...finished processing level 1
[B//] | processing level 1...
[B/1/] | processing level 2...
[B/1/x] | processing level 3...
[B/1/x] | ...finished processing level 3
[B/1/y] | processing level 3...
[B/1/y] | ...finished processing level 3
[B/1/z] | processing level 3...
[B/1/z] | ...finished processing level 3
[B/1/] | ...finished processing level 2
[B/2/] | processing level 2...
[B/2/x] | processing level 3...
[B/2/x] | ...finished processing level 3
[B/2/y] | processing level 3...
[B/2/y] | ...finished processing level 3
[B/2/z] | processing level 3...
[B/2/z] | ...finished processing level 3
[B/2/] | ...finished processing level 2
[B/3/] | processing level 2...
[B/3/x] | processing level 3...
[B/3/x] | ...finished processing level 3
[B/3/y] | processing level 3...
[B/3/y] | ...finished processing level 3
[B/3/z] | processing level 3...
[B/3/z] | ...finished processing level 3
[B/3/] | ...finished processing level 2
[B//] | ...finished processing level 1
[C//] | processing level 1...
[C/1/] | processing level 2...
[C/1/x] | processing level 3...
[C/1/x] | ...finished processing level 3
[C/1/y] | processing level 3...
[C/1/y] | ...finished processing level 3
[C/1/z] | processing level 3...
[C/1/z] | ...finished processing level 3
[C/1/] | ...finished processing level 2
[C/2/] | processing level 2...
[C/2/x] | processing level 3...
[C/2/x] | ...finished processing level 3
[C/2/y] | processing level 3...
[C/2/y] | ...finished processing level 3
[C/2/z] | processing level 3...
[C/2/z] | ...finished processing level 3
[C/2/] | ...finished processing level 2
[C/3/] | processing level 2...
[C/3/x] | processing level 3...
[C/3/x] | ...finished processing level 3
[C/3/y] | processing level 3...
[C/3/y] | ...finished processing level 3
[C/3/z] | processing level 3...
[C/3/z] | ...finished processing level 3
[C/3/] | ...finished processing level 2
[C//] | ...finished processing level 1
[//] | ...finished processing all levels
[//] | ...finished case 4-- using MDCStack






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

Reply via email to