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