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