////
    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.
////

= Thread Context

Just like
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/lang/ThreadLocal.html[Java's `ThreadLocal`],
_Thread Context_ facilitates associating information with the executing thread and making this information accessible to the rest of the logging system.
Thread Context is one of many xref:manual/api.adoc#fish-tagging[_fish tagging_ capabilities provided by Log4j API].

[#usage]
== Usage

The entry point for associating logging-related information with the executing thread is
link:../javadoc/log4j-api/org/apache/logging/log4j/ThreadContext.html[`ThreadContext`].
It offers both

[#mdc]
* map-structured – referred to as _Thread Context Map_ or _Mapped Diagnostic Context (MDC)_
[#ndc]
* stack-structured – referred to as _Thread Context Stack_ or _Nested Diagnostic Context (NDC)_

storage:

[source,java]
----
ThreadContext.put("ipAddress", request.getRemoteAddr()); // <1>
ThreadContext.put("hostName", request.getServerName()); // <1>
ThreadContext.put("loginId", session.getAttribute("loginId")); // <1>

void performWork() {
    ThreadContext.push("performWork()"); // <2>

    LOGGER.debug("Performing work"); // <3>
    // Perform the work

    ThreadContext.pop(); // <4>
}

ThreadContext.clear(); // <5>
----

<1> Adding properties to the thread context map
<2> Pushing properties to the thread context stack
<3> Added properties can later on be used to, for instance, filter the log event, provide extra information in the layout, etc.
<4> Popping the last pushed property from the thread context stack
<5> Clearing the thread context (for both stack and map!)

[#CloseableThreadContext]
=== Auto-clearing thread context

When placing items on the thread context stack or map, it's necessary to remove them again when appropriate.
To assist with this, you can use
link:../javadoc/log4j-api/org/apache/logging/log4j/CloseableThreadContext.html[`CloseableThreadContext`]
(implementing
https://docs.oracle.com/javase/{java-target-version}/docs/api/java/lang/AutoCloseable.html[`AutoCloseable`])
in a try-with-resources block:

[source,java]
----
try (CloseableThreadContext.Instance ignored = CloseableThreadContext
        .put("ipAddress", request.getRemoteAddr()) // <1>
        .push("performWork()")) { // <1>

    LOGGER.debug("Performing work"); // <2>
    // Perform the work

}

// ... // <3>
----

<1> Making thread context changes that will only be visible **within the scope of the try-with-resources block**
<2> Added properties can later on be used to, for instance, filter the log event, provide extra information in the layout, etc.
<3> Outside the scope of the try-with-resources block made thread context changes will not be visible

[#init]
=== Initializing thread context

It is a common use case that a single threaded execution fans out to multiple threads by means of a thread pool.
In such a case, you need to clone the context of the current thread to the ones in the pool.
For that purpose, you can use `putAll()` and `pushAll()` methods that are provided by both `ThreadContext` and `CloseableThreadContext`:

[source,java]
----
LOGGER.debug("Starting background thread for user");

Map<String, String> mdc = ThreadContext.getImmutableContext(); // <1>
List<String> ndc = ThreadContext.getImmutableStack().asList(); // <1>

executor.submit(() -> {
    try (CloseableThreadContext.Instance ignored = CloseableThreadContext
            .putAll(mdc) // <2>
            .pushAll(ndc)) { // <2>

        LOGGER.debug("Processing for user started");
        // ...

    }
});
----

<1> Taking a snapshot of the thread context
<2> Initializing the thread context for the background task

[#config]
== Configuration

Since the thread context is inherently linked to the logging implementation, its configuration options depend on the logging implementation used:

Simple Logger::
+
See xref:manual/simple-logger.adoc#thread-context[Thread context configuration of Simple Logger].

Log4j Core::
+
See xref:manual/systemproperties.adoc#properties-thread-context[Thread context configuration of Log4j Core].

Log4j API to SLF4J bridge::
+
All `ThreadContext` method calls are translated into equivalent
https://www.slf4j.org/api/org/slf4j/MDC.html[`org.slf4j.MDC`]
method calls.

JUL::
+
All `ThreadContext` method calls are a no-op.

[#extending]
== Extending

Certain thread context implementation details can be customized to fit your use case.

[#custom-ContextDataProvider]
=== Custom thread context data provider

The link:../javadoc/log4j-core/org/apache/logging/log4j/core/util/ContextDataProvider.html[`ContextDataProvider`] is an interface applications and libraries can use to inject additional properties into a log events' context data.
Log4j uses `java.util.ServiceLoader` to locate and load `ContextDataProvider` instances.
link:../javadoc/log4j-core/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.html[`ThreadContextDataProvider`] is the default implementation provided.
You can provide a custom `ContextDataProvider` implementation as follows:

. Create the following file in your class path:
+
[source,text]
----
META-INF/services/org.apache.logging.log4j.core.util.ContextDataProvider
----
. Write the fully-qualified class name of your custom implementation (e.g., `com.mycompany.CustomContextDataProvider`) to the file created in the previous step.

==== Third-party custom thread context data providers

[IMPORTANT]
====
These context data providers are supplied by **third-party** vendors and are not maintained by the
link:{logging-services-url}[Apache Logging Services]
(Log4j, Log4cxx, Log4net) project.
====

https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure[OpenTelemetry Context Data Provider]::
Injects trace context data into log events.

https://oss.copernik.eu/tomcat/3.x/components/log4j-tomcat#TomcatContextDataProvider[Copernik.eu Tomcat Context Data Provider]::
Injects the name of the currently active Tomcat engine, host and web application into log events.

[#custom-ThreadContextMap]
=== Custom thread context map

Custom thread context map implementations can be provided by setting <<log4j2.threadContextMap,the `log4j2.threadContextMap` system property>> to the fully-qualified class name of the custom implementation class extending from
link:../javadoc/log4j-api/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`].

While providing a custom thread context map implementation, you are advised to also extend from
link:../javadoc/log4j-api/org/apache/logging/log4j/spi/ReadOnlyThreadContextMap.html[`ReadOnlyThreadContextMap`]
too.
By this way, your custom thread context map implementation will be accessible to applications via
link:../javadoc/log4j-api/org/apache/logging/log4j/ThreadContext.html#getThreadContextMap()[`ThreadContext.getThreadContextMap()`].
