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