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