Uploaded image for project: 'Log4j 2'
  1. Log4j 2
  2. LOG4J2-1517

Add ThreadContext.setContext(Map<String, String>)

    XMLWordPrintableJSON

    Details

    • Type: New Feature
    • Status: Resolved
    • Priority: Major
    • Resolution: Later
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None

      Description

      Add Add ThreadContext.setContext(Map<String, String>).

      Note that we have ThreadContext.setStack(Collection<String>) to set the whole stack but nothing to set the whole map.

      My immediate goal is to be able to build a JUnit Rule to save and restore the thread context around each unit test method and/or a given class.

      I have (not committed yet):

      /**
       * Restores the ThreadContext to it's initial map and stack values after a JUnit test.
       */
      public class ThreadContextRule extends ExternalResource {
      
          private final boolean restoreMap;
          private final boolean restoreStack;
          private ThreadContextHolder threadContextHolder;
      
          /**
           * Constructs an instance initialized to restore the stack and map.
           */
          public ThreadContextRule() {
              this(true, true);
          }
      
          /**
           * Constructs an instance initialized to restore the given structures.
           * 
           * @param restoreMap
           *            Whether to restore the thread context map.
           * @param restoreStack
           *            Whether to restore the thread context stack.
           */
          public ThreadContextRule(final boolean restoreMap, final boolean restoreStack) {
              super();
              this.restoreMap = restoreMap;
              this.restoreStack = restoreStack;
          }
      
          @Override
          protected void after() {
              if (threadContextHolder != null) {
                  threadContextHolder.restore();
              }
          }
      
          @Override
          protected void before() throws Throwable {
              threadContextHolder = new ThreadContextHolder(restoreMap, restoreStack);
              if (restoreMap) {
                  ThreadContext.clearMap();
              }
              if (restoreStack) {
                  ThreadContext.clearStack();
              }
          }
      
      }
      

      and (in src/test):

      /**
       * Holds an immutable copy of the ThreadContext stack and map.
       * 
       * TODO Use LOG4J2-1517 Add ThreadContext.setContext(Map<String, String>)
       * 
       * or
       * 
       * TODO Might be replaced by something from LOG4J2-1447.
       * 
       * or do nothing.
       * 
       * @since 2.7
       */
      public class ThreadContextHolder {
      
          private final Map<String, String> immutableContext;
          private final ContextStack immutableStack;
          private final boolean restoreContext;
          private final boolean restoreStack;
      
          /**
           * Constructs a new holder initialized with an immutable copy of the ThreadContext stack and map.
           * @param restoreContext 
           * @param restoreStack 
           */
          public ThreadContextHolder(final boolean restoreContext, final boolean restoreStack) {
              this.restoreContext = restoreContext;
              this.restoreStack = restoreStack;
              this.immutableContext = restoreContext ? ThreadContext.getImmutableContext() : null;
              this.immutableStack = restoreStack ? ThreadContext.getImmutableStack() : null;
          }
      
          /**
           * Restores the ThreadContext stack and map based on the values saved in the constructor.
           */
          public void restore() {
              if (restoreStack) {
                  ThreadContext.setStack(immutableStack);
              }
              if (restoreContext) {
                  ThreadContext.setContext(immutableContext);
              }
          }
      }
      

      and in ThreadContext:

          /**
           * Sets this thread's context.
           * 
           * @param map The map to use.
           * @since 2.7
           */
          public static void setContext(final Map<String, String> map) {
              if (map.isEmpty() || !useMap) {
                  return;
              }
              contextMap.clear();
              contextMap.putAll(map);
          }
      

      For convenience:

      /**
       * Restores the ThreadContext to it's initial map values after a JUnit test.
       */
      public class ThreadContextMapRule extends ThreadContextRule {
      
          /**
           * Constructs an initialized instance.
           */
          public ThreadContextMapRule() {
              super(true, false);
          }
      }
      
      /**
       * Restores the ThreadContext to it's initial stack values after a JUnit test.
       */
      public class ThreadContextStackRule extends ThreadContextRule {
      
          /**
           * Constructs an initialized instance.
           */
          public ThreadContextStackRule() {
              super(false, true);
          }
      }
      
      

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                ggregory Gary D. Gregory
                Reporter:
                ggregory Gary D. Gregory
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: