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    
018    package org.apache.logging.log4j;
019    
020    import java.io.Serializable;
021    import java.util.AbstractCollection;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.NoSuchElementException;
028    
029    import org.apache.logging.log4j.message.ParameterizedMessage;
030    import org.apache.logging.log4j.spi.DefaultThreadContextMap;
031    import org.apache.logging.log4j.spi.DefaultThreadContextStack;
032    import org.apache.logging.log4j.spi.Provider;
033    import org.apache.logging.log4j.spi.ThreadContextMap;
034    import org.apache.logging.log4j.spi.ThreadContextStack;
035    import org.apache.logging.log4j.status.StatusLogger;
036    import org.apache.logging.log4j.util.PropertiesUtil;
037    import 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     */
046    public 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    }