/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache license, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the license for the specific language governing permissions and
 * limitations under the license.
 */

package org.apache.logging.log4j;

import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.spi.DefaultThreadContextMap;
import org.apache.logging.log4j.spi.DefaultThreadContextStack;
import org.apache.logging.log4j.spi.NoOpThreadContextMap;
import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
import org.apache.logging.log4j.spi.ThreadContextMap;
import org.apache.logging.log4j.spi.ThreadContextMap2;
import org.apache.logging.log4j.spi.CleanableThreadContextMap;
import org.apache.logging.log4j.spi.ThreadContextMapFactory;
import org.apache.logging.log4j.spi.ThreadContextStack;
import org.apache.logging.log4j.util.PropertiesUtil;

The ThreadContext allows applications to store information either in a Map or a Stack.

The MDC is managed on a per thread basis. To enable automatic inheritance of copies of the MDC to newly created threads, enable the "isThreadContextMapInheritable" Log4j system property.

See Also:
/** * The ThreadContext allows applications to store information either in a Map or a Stack. * <p> * <b><em>The MDC is managed on a per thread basis</em></b>. To enable automatic inheritance of <i>copies</i> of the MDC * to newly created threads, enable the {@value DefaultThreadContextMap#INHERITABLE_MAP} Log4j system property. * </p> * @see <a href="https://logging.apache.org/log4j/2.x/manual/thread-context.html">Thread Context Manual</a> */
public final class ThreadContext {
An empty read-only ThreadContextStack.
/** * An empty read-only ThreadContextStack. */
private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack { private static final long serialVersionUID = 1L; private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>(); @Override public String pop() { return null; } @Override public String peek() { return null; } @Override public void push(final String message) { throw new UnsupportedOperationException(); } @Override public int getDepth() { return 0; } @Override public List<String> asList() { return Collections.emptyList(); } @Override public void trim(final int depth) { // Do nothing } @Override public boolean equals(final Object o) { // Similar to java.util.Collections.EmptyList.equals(Object) return (o instanceof Collection) && ((Collection<?>) o).isEmpty(); } @Override public int hashCode() { // Same as java.util.Collections.EmptyList.hashCode() return 1; } @Override public ContextStack copy() { return this; } @Override public <T> T[] toArray(final T[] a) { throw new UnsupportedOperationException(); } @Override public boolean add(final String e) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(final Collection<?> c) { return false; } @Override public boolean addAll(final Collection<? extends String> c) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(final Collection<?> c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(final Collection<?> c) { throw new UnsupportedOperationException(); } @Override public Iterator<String> iterator() { return EMPTY_ITERATOR; } @Override public int size() { return 0; } @Override public ContextStack getImmutableStackOrNull() { return this; } }
An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do.
Type parameters:
  • <E> – the type of the empty iterator
/** * An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do. * * @param <E> the type of the empty iterator */
private static class EmptyIterator<E> implements Iterator<E> { @Override public boolean hasNext() { return false; } @Override public E next() { throw new NoSuchElementException("This is an empty iterator!"); } @Override public void remove() { // no-op } }
Empty, immutable Map.
/** * Empty, immutable Map. */
// ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse @SuppressWarnings("PublicStaticCollectionField") // I like irony, so I won't delete it... public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
Empty, immutable ContextStack.
/** * Empty, immutable ContextStack. */
// ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse @SuppressWarnings("PublicStaticCollectionField") public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack(); private static final String DISABLE_MAP = "disableThreadContextMap"; private static final String DISABLE_STACK = "disableThreadContextStack"; private static final String DISABLE_ALL = "disableThreadContext"; private static boolean disableAll; private static boolean useMap; private static boolean useStack; private static ThreadContextMap contextMap; private static ThreadContextStack contextStack; private static ReadOnlyThreadContextMap readOnlyContextMap; static { init(); } private ThreadContext() { // empty }
Consider private, used for testing.
/** * <em>Consider private, used for testing.</em> */
static void init() { ThreadContextMapFactory.init(); contextMap = null; final PropertiesUtil managerProps = PropertiesUtil.getProperties(); disableAll = managerProps.getBooleanProperty(DISABLE_ALL); useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll); useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll); contextStack = new DefaultThreadContextStack(useStack); if (!useMap) { contextMap = new NoOpThreadContextMap(); } else { contextMap = ThreadContextMapFactory.createThreadContextMap(); } if (contextMap instanceof ReadOnlyThreadContextMap) { readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap; } else { readOnlyContextMap = null; } }
Puts a context value (the value parameter) as identified with the key parameter into the current thread's context map.

If the current thread does not have a context map it is created as a side effect.

Params:
  • key – The key name.
  • value – The key value.
/** * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into * the current thread's context map. * * <p> * If the current thread does not have a context map it is created as a side effect. * </p> * * @param key The key name. * @param value The key value. */
public static void put(final String key, final String value) { contextMap.put(key, value); }
Puts all given context map entries into the current thread's context map.

If the current thread does not have a context map it is created as a side effect.

Params:
  • m – The map.
Since:2.7
/** * Puts all given context map entries into the current thread's * context map. * * <p>If the current thread does not have a context map it is * created as a side effect.</p> * @param m The map. * @since 2.7 */
public static void putAll(final Map<String, String> m) { if (contextMap instanceof ThreadContextMap2) { ((ThreadContextMap2) contextMap).putAll(m); } else if (contextMap instanceof DefaultThreadContextMap) { ((DefaultThreadContextMap) contextMap).putAll(m); } else { for (final Map.Entry<String, String> entry: m.entrySet()) { contextMap.put(entry.getKey(), entry.getValue()); } } }
Gets the context value identified by the key parameter.

This method has no side effects.

Params:
  • key – The key to locate.
Returns:The value associated with the key or null.
/** * Gets the context value identified by the <code>key</code> parameter. * * <p> * This method has no side effects. * </p> * * @param key The key to locate. * @return The value associated with the key or null. */
public static String get(final String key) { return contextMap.get(key); }
Removes the context value identified by the key parameter.
Params:
  • key – The key to remove.
/** * Removes the context value identified by the <code>key</code> parameter. * * @param key The key to remove. */
public static void remove(final String key) { contextMap.remove(key); }
Removes the context values identified by the keys parameter.
Params:
  • keys – The keys to remove.
Since:2.8
/** * Removes the context values identified by the <code>keys</code> parameter. * * @param keys The keys to remove. * * @since 2.8 */
public static void removeAll(final Iterable<String> keys) { if (contextMap instanceof CleanableThreadContextMap) { ((CleanableThreadContextMap) contextMap).removeAll(keys); } else if (contextMap instanceof DefaultThreadContextMap) { ((DefaultThreadContextMap) contextMap).removeAll(keys); } else { for (final String key : keys) { contextMap.remove(key); } } }
Clears the context map.
/** * Clears the context map. */
public static void clearMap() { contextMap.clear(); }
Clears the context map and stack.
/** * Clears the context map and stack. */
public static void clearAll() { clearMap(); clearStack(); }
Determines if the key is in the context.
Params:
  • key – The key to locate.
Returns:True if the key is in the context, false otherwise.
/** * Determines if the key is in the context. * * @param key The key to locate. * @return True if the key is in the context, false otherwise. */
public static boolean containsKey(final String key) { return contextMap.containsKey(key); }
Returns a mutable copy of current thread's context Map.
Returns:a mutable copy of the context.
/** * Returns a mutable copy of current thread's context Map. * * @return a mutable copy of the context. */
public static Map<String, String> getContext() { return contextMap.getCopy(); }
Returns an immutable view of the current thread's context Map.
Returns:An immutable view of the ThreadContext Map.
/** * Returns an immutable view of the current thread's context Map. * * @return An immutable view of the ThreadContext Map. */
public static Map<String, String> getImmutableContext() { final Map<String, String> map = contextMap.getImmutableMapOrNull(); return map == null ? EMPTY_MAP : map; }
Returns a read-only view of the internal data structure used to store thread context key-value pairs, or null if the internal data structure does not implement the ReadOnlyThreadContextMap interface.

The DefaultThreadContextMap implementation does not implement ReadOnlyThreadContextMap, so by default this method returns null.

See Also:
Returns:the internal data structure used to store thread context key-value pairs or null
Since:2.8
/** * Returns a read-only view of the internal data structure used to store thread context key-value pairs, * or {@code null} if the internal data structure does not implement the * {@code ReadOnlyThreadContextMap} interface. * <p> * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by * default this method returns {@code null}. * </p> * * @return the internal data structure used to store thread context key-value pairs or {@code null} * @see ThreadContextMapFactory * @see DefaultThreadContextMap * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap * @since 2.8 */
public static ReadOnlyThreadContextMap getThreadContextMap() { return readOnlyContextMap; }
Returns true if the Map is empty.
Returns:true if the Map is empty, false otherwise.
/** * Returns true if the Map is empty. * * @return true if the Map is empty, false otherwise. */
public static boolean isEmpty() { return contextMap.isEmpty(); }
Clears the stack for this thread.
/** * Clears the stack for this thread. */
public static void clearStack() { contextStack.clear(); }
Returns a copy of this thread's stack.
Returns:A copy of this thread's stack.
/** * Returns a copy of this thread's stack. * * @return A copy of this thread's stack. */
public static ContextStack cloneStack() { return contextStack.copy(); }
Gets an immutable copy of this current thread's context stack.
Returns:an immutable copy of the ThreadContext stack.
/** * Gets an immutable copy of this current thread's context stack. * * @return an immutable copy of the ThreadContext stack. */
public static ContextStack getImmutableStack() { final ContextStack result = contextStack.getImmutableStackOrNull(); return result == null ? EMPTY_STACK : result; }
Sets this thread's stack.
Params:
  • stack – The stack to use.
/** * Sets this thread's stack. * * @param stack The stack to use. */
public static void setStack(final Collection<String> stack) { if (stack.isEmpty() || !useStack) { return; } contextStack.clear(); contextStack.addAll(stack); }
Gets the current nesting depth of this thread's stack.
See Also:
Returns:the number of items in the stack.
/** * Gets the current nesting depth of this thread's stack. * * @return the number of items in the stack. * * @see #trim */
public static int getDepth() { return contextStack.getDepth(); }
Returns the value of the last item placed on the stack.

The returned value is the value that was pushed last. If no context is available, then the empty string "" is returned.

Returns:String The innermost diagnostic context.
/** * Returns the value of the last item placed on the stack. * * <p> * The returned value is the value that was pushed last. If no context is available, then the empty string "" is * returned. * </p> * * @return String The innermost diagnostic context. */
public static String pop() { return contextStack.pop(); }
Looks at the last diagnostic context at the top of this NDC without removing it.

The returned value is the value that was pushed last. If no context is available, then the empty string "" is returned.

Returns:String The innermost diagnostic context.
/** * Looks at the last diagnostic context at the top of this NDC without removing it. * * <p> * The returned value is the value that was pushed last. If no context is available, then the empty string "" is * returned. * </p> * * @return String The innermost diagnostic context. */
public static String peek() { return contextStack.peek(); }
Pushes new diagnostic context information for the current thread.

The contents of the message parameter is determined solely by the client.

Params:
  • message – The new diagnostic context information.
/** * Pushes new diagnostic context information for the current thread. * * <p> * The contents of the <code>message</code> parameter is determined solely by the client. * </p> * * @param message The new diagnostic context information. */
public static void push(final String message) { contextStack.push(message); }
Pushes new diagnostic context information for the current thread.

The contents of the message and args parameters are determined solely by the client. The message will be treated as a format String and tokens will be replaced with the String value of the arguments in accordance with ParameterizedMessage.

Params:
  • message – The new diagnostic context information.
  • args – Parameters for the message.
/** * Pushes new diagnostic context information for the current thread. * * <p> * The contents of the <code>message</code> and args parameters are determined solely by the client. The message * will be treated as a format String and tokens will be replaced with the String value of the arguments in * accordance with ParameterizedMessage. * </p> * * @param message The new diagnostic context information. * @param args Parameters for the message. */
public static void push(final String message, final Object... args) { contextStack.push(ParameterizedMessage.format(message, args)); }
Removes the diagnostic context for this thread.

Each thread that created a diagnostic context by calling push should call this method before exiting. Otherwise, the memory used by the thread cannot be reclaimed by the VM.

As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that the remove method is called before exiting a thread, this method has been augmented to lazily remove references to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call remove before exiting a thread. However, you must call remove sometime. If you never call it, then your application is sure to run out of memory.

/** * Removes the diagnostic context for this thread. * * <p> * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting. * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM. * </p> * * <p> * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that * the remove method is called before exiting a thread, this method has been augmented to lazily remove references * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call * it, then your application is sure to run out of memory. * </p> */
public static void removeStack() { contextStack.clear(); }
Trims elements from this diagnostic context. If the current depth is smaller or equal to maxDepth, then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are discarded.

This method is a convenient alternative to multiple pop calls. Moreover, it is often the case that at the end of complex call sequences, the depth of the ThreadContext is unpredictable. The trim method circumvents this problem.

For example, the combination

void foo() {
    final int depth = ThreadContext.getDepth();
    // ... complex sequence of calls
    ThreadContext.trim(depth);
}

ensures that between the entry and exit of foo the depth of the diagnostic stack is conserved.

Params:
  • depth – The number of elements to keep.
See Also:
/** * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>, * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are * discarded. * * <p> * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method * circumvents this problem. * </p> * * <p> * For example, the combination * </p> * * <pre> * void foo() { * final int depth = ThreadContext.getDepth(); * * // ... complex sequence of calls * * ThreadContext.trim(depth); * } * </pre> * * <p> * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved. * </p> * * @see #getDepth * @param depth The number of elements to keep. */
public static void trim(final int depth) { contextStack.trim(depth); }
The ThreadContext Stack interface.
/** * The ThreadContext Stack interface. */
public interface ContextStack extends Serializable, Collection<String> {
Returns the element at the top of the stack.
Throws:
Returns:The element at the top of the stack.
/** * Returns the element at the top of the stack. * * @return The element at the top of the stack. * @throws java.util.NoSuchElementException if the stack is empty. */
String pop();
Returns the element at the top of the stack without removing it or null if the stack is empty.
Returns:the element at the top of the stack or null if the stack is empty.
/** * Returns the element at the top of the stack without removing it or null if the stack is empty. * * @return the element at the top of the stack or null if the stack is empty. */
String peek();
Pushes an element onto the stack.
Params:
  • message – The element to add.
/** * Pushes an element onto the stack. * * @param message The element to add. */
void push(String message);
Returns the number of elements in the stack.
Returns:the number of elements in the stack.
/** * Returns the number of elements in the stack. * * @return the number of elements in the stack. */
int getDepth();
Returns all the elements in the stack in a List.
Returns:all the elements in the stack in a List.
/** * Returns all the elements in the stack in a List. * * @return all the elements in the stack in a List. */
List<String> asList();
Trims elements from the end of the stack.
Params:
  • depth – The maximum number of items in the stack to keep.
/** * Trims elements from the end of the stack. * * @param depth The maximum number of items in the stack to keep. */
void trim(int depth);
Returns a copy of the ContextStack.
Returns:a copy of the ContextStack.
/** * Returns a copy of the ContextStack. * * @return a copy of the ContextStack. */
ContextStack copy();
Returns a ContextStack with the same contents as this ContextStack or null. Attempts to modify the returned stack may or may not throw an exception, but will not affect the contents of this ContextStack.
Returns:a ContextStack with the same contents as this ContextStack or null.
/** * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack. * * @return a ContextStack with the same contents as this ContextStack or {@code null}. */
ContextStack getImmutableStackOrNull(); } }