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        ThreadContextMapFactory.init();
215        contextMap = null;
216        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
217        disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
218        useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
219        useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
220
221        contextStack = new DefaultThreadContextStack(useStack);
222        if (!useMap) {
223            contextMap = new NoOpThreadContextMap();
224        } else {
225            contextMap = ThreadContextMapFactory.createThreadContextMap();
226        }
227        if (contextMap instanceof ReadOnlyThreadContextMap) {
228            readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
229        } else {
230            readOnlyContextMap = null;
231        }
232    }
233
234    /**
235     * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
236     * the current thread's context map.
237     *
238     * <p>
239     * If the current thread does not have a context map it is created as a side effect.
240     * </p>
241     *
242     * @param key The key name.
243     * @param value The key value.
244     */
245    public static void put(final String key, final String value) {
246        contextMap.put(key, value);
247    }
248
249    /**
250     * Puts all given context map entries into the current thread's
251     * context map.
252     *
253     * <p>If the current thread does not have a context map it is
254     * created as a side effect.</p>
255     * @param m The map.
256     * @since 2.7
257     */
258    public static void putAll(final Map<String, String> m) {
259        if (contextMap instanceof ThreadContextMap2) {
260            ((ThreadContextMap2) contextMap).putAll(m);
261        } else if (contextMap instanceof DefaultThreadContextMap) {
262            ((DefaultThreadContextMap) contextMap).putAll(m);
263        } else {
264            for (final Map.Entry<String, String> entry: m.entrySet()) {
265                contextMap.put(entry.getKey(), entry.getValue());
266            }
267        }
268    }
269
270    /**
271     * Gets the context value identified by the <code>key</code> parameter.
272     *
273     * <p>
274     * This method has no side effects.
275     * </p>
276     *
277     * @param key The key to locate.
278     * @return The value associated with the key or null.
279     */
280    public static String get(final String key) {
281        return contextMap.get(key);
282    }
283
284    /**
285     * Removes the context value identified by the <code>key</code> parameter.
286     *
287     * @param key The key to remove.
288     */
289    public static void remove(final String key) {
290        contextMap.remove(key);
291    }
292
293    /**
294     * Removes the context values identified by the <code>keys</code> parameter.
295     *
296     * @param keys The keys to remove.
297     *
298     * @since 2.8
299     */
300    public static void removeAll(final Iterable<String> keys) {
301        if (contextMap instanceof CleanableThreadContextMap) {
302            ((CleanableThreadContextMap) contextMap).removeAll(keys);
303        } else if (contextMap instanceof DefaultThreadContextMap) {
304            ((DefaultThreadContextMap) contextMap).removeAll(keys);
305        } else {
306            for (final String key : keys) {
307                contextMap.remove(key);
308            }
309        }
310    }
311
312    /**
313     * Clears the context map.
314     */
315    public static void clearMap() {
316        contextMap.clear();
317    }
318
319    /**
320     * Clears the context map and stack.
321     */
322    public static void clearAll() {
323        clearMap();
324        clearStack();
325    }
326
327    /**
328     * Determines if the key is in the context.
329     *
330     * @param key The key to locate.
331     * @return True if the key is in the context, false otherwise.
332     */
333    public static boolean containsKey(final String key) {
334        return contextMap.containsKey(key);
335    }
336
337    /**
338     * Returns a mutable copy of current thread's context Map.
339     *
340     * @return a mutable copy of the context.
341     */
342    public static Map<String, String> getContext() {
343        return contextMap.getCopy();
344    }
345
346    /**
347     * Returns an immutable view of the current thread's context Map.
348     *
349     * @return An immutable view of the ThreadContext Map.
350     */
351    public static Map<String, String> getImmutableContext() {
352        final Map<String, String> map = contextMap.getImmutableMapOrNull();
353        return map == null ? EMPTY_MAP : map;
354    }
355
356    /**
357     * Returns a read-only view of the internal data structure used to store thread context key-value pairs,
358     * or {@code null} if the internal data structure does not implement the
359     * {@code ReadOnlyThreadContextMap} interface.
360     * <p>
361     * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by
362     * default this method returns {@code null}.
363     * </p>
364     *
365     * @return the internal data structure used to store thread context key-value pairs or {@code null}
366     * @see ThreadContextMapFactory
367     * @see DefaultThreadContextMap
368     * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap
369     * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap
370     * @since 2.8
371     */
372    public static ReadOnlyThreadContextMap getThreadContextMap() {
373        return readOnlyContextMap;
374    }
375
376    /**
377     * Returns true if the Map is empty.
378     *
379     * @return true if the Map is empty, false otherwise.
380     */
381    public static boolean isEmpty() {
382        return contextMap.isEmpty();
383    }
384
385    /**
386     * Clears the stack for this thread.
387     */
388    public static void clearStack() {
389        contextStack.clear();
390    }
391
392    /**
393     * Returns a copy of this thread's stack.
394     *
395     * @return A copy of this thread's stack.
396     */
397    public static ContextStack cloneStack() {
398        return contextStack.copy();
399    }
400
401    /**
402     * Gets an immutable copy of this current thread's context stack.
403     *
404     * @return an immutable copy of the ThreadContext stack.
405     */
406    public static ContextStack getImmutableStack() {
407        final ContextStack result = contextStack.getImmutableStackOrNull();
408        return result == null ? EMPTY_STACK : result;
409    }
410
411    /**
412     * Sets this thread's stack.
413     *
414     * @param stack The stack to use.
415     */
416    public static void setStack(final Collection<String> stack) {
417        if (stack.isEmpty() || !useStack) {
418            return;
419        }
420        contextStack.clear();
421        contextStack.addAll(stack);
422    }
423
424    /**
425     * Gets the current nesting depth of this thread's stack.
426     *
427     * @return the number of items in the stack.
428     *
429     * @see #trim
430     */
431    public static int getDepth() {
432        return contextStack.getDepth();
433    }
434
435    /**
436     * Returns the value of the last item placed on the stack.
437     *
438     * <p>
439     * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
440     * returned.
441     * </p>
442     *
443     * @return String The innermost diagnostic context.
444     */
445    public static String pop() {
446        return contextStack.pop();
447    }
448
449    /**
450     * Looks at the last diagnostic context at the top of this NDC without removing it.
451     *
452     * <p>
453     * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
454     * returned.
455     * </p>
456     *
457     * @return String The innermost diagnostic context.
458     */
459    public static String peek() {
460        return contextStack.peek();
461    }
462
463    /**
464     * Pushes new diagnostic context information for the current thread.
465     *
466     * <p>
467     * The contents of the <code>message</code> parameter is determined solely by the client.
468     * </p>
469     *
470     * @param message The new diagnostic context information.
471     */
472    public static void push(final String message) {
473        contextStack.push(message);
474    }
475
476    /**
477     * Pushes new diagnostic context information for the current thread.
478     *
479     * <p>
480     * The contents of the <code>message</code> and args parameters are determined solely by the client. The message
481     * will be treated as a format String and tokens will be replaced with the String value of the arguments in
482     * accordance with ParameterizedMessage.
483     * </p>
484     *
485     * @param message The new diagnostic context information.
486     * @param args Parameters for the message.
487     */
488    public static void push(final String message, final Object... args) {
489        contextStack.push(ParameterizedMessage.format(message, args));
490    }
491
492    /**
493     * Removes the diagnostic context for this thread.
494     *
495     * <p>
496     * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting.
497     * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM.
498     * </p>
499     *
500     * <p>
501     * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that
502     * the remove method is called before exiting a thread, this method has been augmented to lazily remove references
503     * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call
504     * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call
505     * it, then your application is sure to run out of memory.
506     * </p>
507     */
508    public static void removeStack() {
509        contextStack.clear();
510    }
511
512    /**
513     * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>,
514     * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are
515     * discarded.
516     *
517     * <p>
518     * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at
519     * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method
520     * circumvents this problem.
521     * </p>
522     *
523     * <p>
524     * For example, the combination
525     * </p>
526     *
527     * <pre>
528     * void foo() {
529     *     final int depth = ThreadContext.getDepth();
530     *
531     *     // ... complex sequence of calls
532     *
533     *     ThreadContext.trim(depth);
534     * }
535     * </pre>
536     *
537     * <p>
538     * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved.
539     * </p>
540     *
541     * @see #getDepth
542     * @param depth The number of elements to keep.
543     */
544    public static void trim(final int depth) {
545        contextStack.trim(depth);
546    }
547
548    /**
549     * The ThreadContext Stack interface.
550     */
551    public interface ContextStack extends Serializable, Collection<String> {
552
553        /**
554         * Returns the element at the top of the stack.
555         *
556         * @return The element at the top of the stack.
557         * @throws java.util.NoSuchElementException if the stack is empty.
558         */
559        String pop();
560
561        /**
562         * Returns the element at the top of the stack without removing it or null if the stack is empty.
563         *
564         * @return the element at the top of the stack or null if the stack is empty.
565         */
566        String peek();
567
568        /**
569         * Pushes an element onto the stack.
570         *
571         * @param message The element to add.
572         */
573        void push(String message);
574
575        /**
576         * Returns the number of elements in the stack.
577         *
578         * @return the number of elements in the stack.
579         */
580        int getDepth();
581
582        /**
583         * Returns all the elements in the stack in a List.
584         *
585         * @return all the elements in the stack in a List.
586         */
587        List<String> asList();
588
589        /**
590         * Trims elements from the end of the stack.
591         *
592         * @param depth The maximum number of items in the stack to keep.
593         */
594        void trim(int depth);
595
596        /**
597         * Returns a copy of the ContextStack.
598         *
599         * @return a copy of the ContextStack.
600         */
601        ContextStack copy();
602
603        /**
604         * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the
605         * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack.
606         *
607         * @return a ContextStack with the same contents as this ContextStack or {@code null}.
608         */
609        ContextStack getImmutableStackOrNull();
610    }
611}