View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  
18  package org.apache.logging.log4j;
19  
20  import java.io.Serializable;
21  import java.util.AbstractCollection;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.NoSuchElementException;
28  
29  import org.apache.logging.log4j.message.ParameterizedMessage;
30  import org.apache.logging.log4j.spi.DefaultThreadContextMap;
31  import org.apache.logging.log4j.spi.DefaultThreadContextStack;
32  import org.apache.logging.log4j.spi.NoOpThreadContextMap;
33  import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
34  import org.apache.logging.log4j.spi.ThreadContextMap;
35  import org.apache.logging.log4j.spi.ThreadContextMap2;
36  import org.apache.logging.log4j.spi.CleanableThreadContextMap;
37  import org.apache.logging.log4j.spi.ThreadContextMapFactory;
38  import org.apache.logging.log4j.spi.ThreadContextStack;
39  import org.apache.logging.log4j.util.PropertiesUtil;
40  
41  /**
42   * The ThreadContext allows applications to store information either in a Map or a Stack.
43   * <p>
44   * <b><em>The MDC is managed on a per thread basis</em></b>. A child thread automatically inherits a <em>copy</em> of
45   * the mapped diagnostic context of its parent.
46   * </p>
47   */
48  public final class ThreadContext {
49  
50      /**
51       * An empty read-only ThreadContextStack.
52       */
53      private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack {
54  
55          private static final long serialVersionUID = 1L;
56  
57          private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>();
58  
59          @Override
60          public String pop() {
61              return null;
62          }
63  
64          @Override
65          public String peek() {
66              return null;
67          }
68  
69          @Override
70          public void push(final String message) {
71              throw new UnsupportedOperationException();
72          }
73  
74          @Override
75          public int getDepth() {
76              return 0;
77          }
78  
79          @Override
80          public List<String> asList() {
81              return Collections.emptyList();
82          }
83  
84          @Override
85          public void trim(final int depth) {
86              // Do nothing
87          }
88  
89          @Override
90          public boolean equals(final Object o) {
91              // Similar to java.util.Collections.EmptyList.equals(Object)
92              return (o instanceof Collection) && ((Collection<?>) o).isEmpty();
93          }
94  
95          @Override
96          public int hashCode() {
97              // Same as java.util.Collections.EmptyList.hashCode()
98              return 1;
99          }
100 
101         @Override
102         public ContextStack copy() {
103             return this;
104         }
105 
106         @Override
107         public <T> T[] toArray(final T[] a) {
108             throw new UnsupportedOperationException();
109         }
110 
111         @Override
112         public boolean add(final String e) {
113             throw new UnsupportedOperationException();
114         }
115 
116         @Override
117         public boolean containsAll(final Collection<?> c) {
118             return false;
119         }
120 
121         @Override
122         public boolean addAll(final Collection<? extends String> c) {
123             throw new UnsupportedOperationException();
124         }
125 
126         @Override
127         public boolean removeAll(final Collection<?> c) {
128             throw new UnsupportedOperationException();
129         }
130 
131         @Override
132         public boolean retainAll(final Collection<?> c) {
133             throw new UnsupportedOperationException();
134         }
135 
136         @Override
137         public Iterator<String> iterator() {
138             return EMPTY_ITERATOR;
139         }
140 
141         @Override
142         public int size() {
143             return 0;
144         }
145 
146         @Override
147         public ContextStack getImmutableStackOrNull() {
148             return this;
149         }
150     }
151 
152     /**
153      * An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do.
154      *
155      * @param <E> the type of the empty iterator
156      */
157     private static class EmptyIterator<E> implements Iterator<E> {
158 
159         @Override
160         public boolean hasNext() {
161             return false;
162         }
163 
164         @Override
165         public E next() {
166             throw new NoSuchElementException("This is an empty iterator!");
167         }
168 
169         @Override
170         public void remove() {
171             // no-op
172         }
173     }
174 
175     /**
176      * Empty, immutable Map.
177      */
178     // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
179     @SuppressWarnings("PublicStaticCollectionField")
180     // I like irony, so I won't delete it...
181     public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
182 
183     /**
184      * Empty, immutable ContextStack.
185      */
186     // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
187     @SuppressWarnings("PublicStaticCollectionField")
188     public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
189 
190     private static final String DISABLE_MAP = "disableThreadContextMap";
191     private static final String DISABLE_STACK = "disableThreadContextStack";
192     private static final String DISABLE_ALL = "disableThreadContext";
193 
194     private static boolean disableAll;
195     private static boolean useMap;
196     private static boolean useStack;
197     private static ThreadContextMap contextMap;
198     private static ThreadContextStack contextStack;
199     private static ReadOnlyThreadContextMap readOnlyContextMap;
200 
201     static {
202         init();
203     }
204 
205     private ThreadContext() {
206         // empty
207     }
208 
209     /**
210      * <em>Consider private, used for testing.</em>
211      */
212     static void init() {
213         contextMap = null;
214         final PropertiesUtil managerProps = PropertiesUtil.getProperties();
215         disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
216         useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
217         useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
218 
219         contextStack = new DefaultThreadContextStack(useStack);
220         if (!useMap) {
221             contextMap = new NoOpThreadContextMap();
222         } else {
223             contextMap = ThreadContextMapFactory.createThreadContextMap();
224         }
225         if (contextMap instanceof ReadOnlyThreadContextMap) {
226             readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
227         }
228     }
229 
230     /**
231      * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
232      * the current thread's context map.
233      *
234      * <p>
235      * If the current thread does not have a context map it is created as a side effect.
236      * </p>
237      *
238      * @param key The key name.
239      * @param value The key value.
240      */
241     public static void put(final String key, final String value) {
242         contextMap.put(key, value);
243     }
244 
245     /**
246      * Puts all given context map entries into the current thread's
247      * context map.
248      *
249      * <p>If the current thread does not have a context map it is
250      * created as a side effect.</p>
251      * @param m The map.
252      * @since 2.7
253      */
254     public static void putAll(final Map<String, String> m) {
255         if (contextMap instanceof ThreadContextMap2) {
256             ((ThreadContextMap2) contextMap).putAll(m);
257         } else if (contextMap instanceof DefaultThreadContextMap) {
258             ((DefaultThreadContextMap) contextMap).putAll(m);
259         } else {
260             for (final Map.Entry<String, String> entry: m.entrySet()) {
261                 contextMap.put(entry.getKey(), entry.getValue());
262             }
263         }
264     }
265 
266     /**
267      * Gets the context value identified by the <code>key</code> parameter.
268      *
269      * <p>
270      * This method has no side effects.
271      * </p>
272      *
273      * @param key The key to locate.
274      * @return The value associated with the key or null.
275      */
276     public static String get(final String key) {
277         return contextMap.get(key);
278     }
279 
280     /**
281      * Removes the context value identified by the <code>key</code> parameter.
282      *
283      * @param key The key to remove.
284      */
285     public static void remove(final String key) {
286         contextMap.remove(key);
287     }
288 
289     /**
290      * Removes the context values identified by the <code>keys</code> parameter.
291      *
292      * @param keys The keys to remove.
293      *
294      * @since 2.8
295      */
296     public static void removeAll(final Iterable<String> keys) {
297         if (contextMap instanceof CleanableThreadContextMap) {
298             ((CleanableThreadContextMap) contextMap).removeAll(keys);
299         } else if (contextMap instanceof DefaultThreadContextMap) {
300             ((DefaultThreadContextMap) contextMap).removeAll(keys);
301         } else {
302             for (final String key : keys) {
303                 contextMap.remove(key);
304             }
305         }
306     }
307 
308     /**
309      * Clears the context map.
310      */
311     public static void clearMap() {
312         contextMap.clear();
313     }
314 
315     /**
316      * Clears the context map and stack.
317      */
318     public static void clearAll() {
319         clearMap();
320         clearStack();
321     }
322 
323     /**
324      * Determines if the key is in the context.
325      *
326      * @param key The key to locate.
327      * @return True if the key is in the context, false otherwise.
328      */
329     public static boolean containsKey(final String key) {
330         return contextMap.containsKey(key);
331     }
332 
333     /**
334      * Returns a mutable copy of current thread's context Map.
335      *
336      * @return a mutable copy of the context.
337      */
338     public static Map<String, String> getContext() {
339         return contextMap.getCopy();
340     }
341 
342     /**
343      * Returns an immutable view of the current thread's context Map.
344      *
345      * @return An immutable view of the ThreadContext Map.
346      */
347     public static Map<String, String> getImmutableContext() {
348         final Map<String, String> map = contextMap.getImmutableMapOrNull();
349         return map == null ? EMPTY_MAP : map;
350     }
351 
352     /**
353      * Returns a read-only view of the internal data structure used to store thread context key-value pairs,
354      * or {@code null} if the internal data structure does not implement the
355      * {@code ReadOnlyThreadContextMap} interface.
356      * <p>
357      * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by
358      * default this method returns {@code null}.
359      * </p>
360      *
361      * @return the internal data structure used to store thread context key-value pairs or {@code null}
362      * @see ThreadContextMapFactory
363      * @see DefaultThreadContextMap
364      * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap
365      * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap
366      * @since 2.8
367      */
368     public static ReadOnlyThreadContextMap getThreadContextMap() {
369         return readOnlyContextMap;
370     }
371 
372     /**
373      * Returns true if the Map is empty.
374      *
375      * @return true if the Map is empty, false otherwise.
376      */
377     public static boolean isEmpty() {
378         return contextMap.isEmpty();
379     }
380 
381     /**
382      * Clears the stack for this thread.
383      */
384     public static void clearStack() {
385         contextStack.clear();
386     }
387 
388     /**
389      * Returns a copy of this thread's stack.
390      *
391      * @return A copy of this thread's stack.
392      */
393     public static ContextStack cloneStack() {
394         return contextStack.copy();
395     }
396 
397     /**
398      * Gets an immutable copy of this current thread's context stack.
399      *
400      * @return an immutable copy of the ThreadContext stack.
401      */
402     public static ContextStack getImmutableStack() {
403         final ContextStack result = contextStack.getImmutableStackOrNull();
404         return result == null ? EMPTY_STACK : result;
405     }
406 
407     /**
408      * Sets this thread's stack.
409      *
410      * @param stack The stack to use.
411      */
412     public static void setStack(final Collection<String> stack) {
413         if (stack.isEmpty() || !useStack) {
414             return;
415         }
416         contextStack.clear();
417         contextStack.addAll(stack);
418     }
419 
420     /**
421      * Gets the current nesting depth of this thread's stack.
422      *
423      * @return the number of items in the stack.
424      *
425      * @see #trim
426      */
427     public static int getDepth() {
428         return contextStack.getDepth();
429     }
430 
431     /**
432      * Returns the value of the last item placed on the stack.
433      *
434      * <p>
435      * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
436      * returned.
437      * </p>
438      *
439      * @return String The innermost diagnostic context.
440      */
441     public static String pop() {
442         return contextStack.pop();
443     }
444 
445     /**
446      * Looks at the last diagnostic context at the top of this NDC without removing it.
447      *
448      * <p>
449      * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
450      * returned.
451      * </p>
452      *
453      * @return String The innermost diagnostic context.
454      */
455     public static String peek() {
456         return contextStack.peek();
457     }
458 
459     /**
460      * Pushes new diagnostic context information for the current thread.
461      *
462      * <p>
463      * The contents of the <code>message</code> parameter is determined solely by the client.
464      * </p>
465      *
466      * @param message The new diagnostic context information.
467      */
468     public static void push(final String message) {
469         contextStack.push(message);
470     }
471 
472     /**
473      * Pushes new diagnostic context information for the current thread.
474      *
475      * <p>
476      * The contents of the <code>message</code> and args parameters are determined solely by the client. The message
477      * will be treated as a format String and tokens will be replaced with the String value of the arguments in
478      * accordance with ParameterizedMessage.
479      * </p>
480      *
481      * @param message The new diagnostic context information.
482      * @param args Parameters for the message.
483      */
484     public static void push(final String message, final Object... args) {
485         contextStack.push(ParameterizedMessage.format(message, args));
486     }
487 
488     /**
489      * Removes the diagnostic context for this thread.
490      *
491      * <p>
492      * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting.
493      * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM.
494      * </p>
495      *
496      * <p>
497      * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that
498      * the remove method is called before exiting a thread, this method has been augmented to lazily remove references
499      * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call
500      * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call
501      * it, then your application is sure to run out of memory.
502      * </p>
503      */
504     public static void removeStack() {
505         contextStack.clear();
506     }
507 
508     /**
509      * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>,
510      * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are
511      * discarded.
512      *
513      * <p>
514      * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at
515      * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method
516      * circumvents this problem.
517      * </p>
518      *
519      * <p>
520      * For example, the combination
521      * </p>
522      *
523      * <pre>
524      * void foo() {
525      *     final int depth = ThreadContext.getDepth();
526      *
527      *     // ... complex sequence of calls
528      *
529      *     ThreadContext.trim(depth);
530      * }
531      * </pre>
532      *
533      * <p>
534      * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved.
535      * </p>
536      *
537      * @see #getDepth
538      * @param depth The number of elements to keep.
539      */
540     public static void trim(final int depth) {
541         contextStack.trim(depth);
542     }
543 
544     /**
545      * The ThreadContext Stack interface.
546      */
547     public interface ContextStack extends Serializable, Collection<String> {
548 
549         /**
550          * Returns the element at the top of the stack.
551          *
552          * @return The element at the top of the stack.
553          * @throws java.util.NoSuchElementException if the stack is empty.
554          */
555         String pop();
556 
557         /**
558          * Returns the element at the top of the stack without removing it or null if the stack is empty.
559          *
560          * @return the element at the top of the stack or null if the stack is empty.
561          */
562         String peek();
563 
564         /**
565          * Pushes an element onto the stack.
566          *
567          * @param message The element to add.
568          */
569         void push(String message);
570 
571         /**
572          * Returns the number of elements in the stack.
573          *
574          * @return the number of elements in the stack.
575          */
576         int getDepth();
577 
578         /**
579          * Returns all the elements in the stack in a List.
580          *
581          * @return all the elements in the stack in a List.
582          */
583         List<String> asList();
584 
585         /**
586          * Trims elements from the end of the stack.
587          *
588          * @param depth The maximum number of items in the stack to keep.
589          */
590         void trim(int depth);
591 
592         /**
593          * Returns a copy of the ContextStack.
594          *
595          * @return a copy of the ContextStack.
596          */
597         ContextStack copy();
598 
599         /**
600          * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the
601          * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack.
602          *
603          * @return a ContextStack with the same contents as this ContextStack or {@code null}.
604          */
605         ContextStack getImmutableStackOrNull();
606     }
607 }