Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Log4j 2's ThreadContext #207

Merged
merged 2 commits into from
Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mvn/javadoc/package-list
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ nl.talsmasoftware.context.metrics
nl.talsmasoftware.context.locale
nl.talsmasoftware.context.mdc
nl.talsmasoftware.context.slf4j.mdc
nl.talsmasoftware.context.log4j2.threadcontext
nl.talsmasoftware.context.opentracing
nl.talsmasoftware.context.servletrequest
nl.talsmasoftware.context.springsecurity
18 changes: 18 additions & 0 deletions context-propagation-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,24 @@
<classifier>sources</classifier>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>log4j2-propagation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>log4j2-propagation</artifactId>
<version>${project.version}</version>
<classifier>javadoc</classifier>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>log4j2-propagation</artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>locale-context</artifactId>
Expand Down
41 changes: 41 additions & 0 deletions log4j2-propagation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[![Maven Version][maven-img]][maven]

# Log4j 2 Thread Context propagation library

Adding the `log4j2-propagation` jar to your classpath
is all that is needed to let the [Thread Context][thread-context]
from the [Log4j 2 library][log4j2] be automatically included into
the `ContextSnapshot`.
sjoerdtalsma marked this conversation as resolved.
Show resolved Hide resolved

## How to use this library

Add it to your classpath.
```xml
<dependency>
<groupId>nl.talsmasoftware.context</groupId>
<artifactId>log4j2-propagation</artifactId>
<version>[see Maven badge above]</version>
</dependency>
```

Done!

Now the data of the Log4j 2 Thread Context is copied into each snapshot
from the `ContextManagers.createSnapshot()` method
to be reactivated by the `Contextsnapshot.reactivate()` call.
The `ContextAwareExecutorService` automatically propagates the full
Thread Context data into all executed tasks this way.

When Thread Context data is propagated, it is added on top of the existing
data, if any: Thread Context stack values are pushed on top of the existing
stack; map entries are added to the existing map, only replacing existing
ones in case of a map key conflict.

Calling `ContextManagers.clearActiveContexts()` will clear the Thread Context
data of the current thread.

[maven-img]: https://img.shields.io/maven-central/v/nl.talsmasoftware.context/log4j2-propagation
[maven]: https://search.maven.org/artifact/nl.talsmasoftware.context/log4j2-propagation

[log4j2]: https://logging.apache.org/log4j/2.x/index.html
[thread-context]: https://logging.apache.org/log4j/2.x/manual/thread-context.html
54 changes: 54 additions & 0 deletions log4j2-propagation/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2016-2021 Talsma ICT

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

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>nl.talsmasoftware.context</groupId>
<artifactId>context-propagation-root</artifactId>
<version>1.0.9-SNAPSHOT</version>
</parent>

<!-- Artifact identification -->
<artifactId>log4j2-propagation</artifactId>
<name>Propagation of Log4j 2 ThreadContext</name>
<packaging>jar</packaging>

<properties>
<!-- Latest Log4j 2 versions require Java >= 8; however this project might also support older versions -->
<maven.compiler.source>1.5</maven.compiler.source>
<maven.compiler.target>1.5</maven.compiler.target>
<project.moduleName>${project.groupId}.log4j2</project.moduleName>
<root.basedir>${project.parent.basedir}</root.basedir>
</properties>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>context-propagation</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2016-2021 Talsma ICT
*
* Licensed 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 nl.talsmasoftware.context.log4j2.threadcontext;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.ThreadContext;

/**
* Snapshot of the data from the Log4j 2 {@link ThreadContext} of a
* specific thread at a certain point in the past.
*/
public class Log4j2ThreadContextData {
private final Map<String, String> contextMap;
private final List<String> contextStack;

/**
* Applies the data to the current thread.
*
* @param data data to apply, may be {@code null}
* @param overwrite whether all existing data should overwritten
*/
static void applyToCurrentThread(Log4j2ThreadContextData data, boolean overwrite) {
if (overwrite) {
ThreadContext.clearAll();
}
if (data != null) {
data.applyToCurrentThread();
}
}

/**
* Applies the data on top of the {@code ThreadContext} of the current thread.
* Conflicting entries are overwritten but all other existing data is kept.
*/
void applyToCurrentThread() {
ThreadContext.putAll(contextMap);

// There is currently no method for pushing a collection, therefore have to
// push one by one
for (String element : contextStack) {
ThreadContext.push(element);
}
}

private Log4j2ThreadContextData(Map<String, String> contextMap, List<String> contextStack) {
this.contextMap = Collections.unmodifiableMap(contextMap);
this.contextStack = Collections.unmodifiableList(contextStack);
}

/**
* Captures the {@code ThreadContext} data of the current thread.
*
* @return data representing the {@code ThreadContext} of the current thread
*/
static Log4j2ThreadContextData fromCurrentThreadContext() {
// Get a copy of context map and context stack
return new Log4j2ThreadContextData(ThreadContext.getContext(), ThreadContext.getImmutableStack().asList());
}

/**
* Returns an unmodifiable view of the {@code ThreadContext} map contained
* in this snapshot.
*
* @return {@code ThreadContext} map contained in this snapshot
*/
public Map<String, String> getContextMap() {
return contextMap;
}

/**
* Returns an unmodifiable view of the {@code ThreadContext} stack contained
* in this snapshot. The elements are ordered from least recently added at
* the beginning of the list to most recently added at the end.
*
* @return {@code ThreadContext} stack contained in this snapshot
*/
public List<String> getContextStack() {
return contextStack;
}

@Override
public String toString() {
return "Log4j2ThreadContextData{"
+ "map=" + contextMap
+ ",stack=" + contextStack
+ '}';
}
}
Loading