Skip to content

Commit d0dd857

Browse files
rgoersppkarwasz
authored andcommitted
Add Scoped context
This PR restores the scoped context introduced in #2438 into the `2.25.x` branch.
1 parent d659fd2 commit d0dd857

File tree

52 files changed

+3789
-212
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+3789
-212
lines changed

log4j-api-test/pom.xml

+6-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<bnd-module-name>org.apache.logging.log4j.test</bnd-module-name>
3838
<bnd-extra-package-options>
3939
org.apache.commons.lang3.*;resolution:=optional,
40+
org.assertj.*;resolution:=optional,
4041
<!-- Both JUnit 4 and JUnit 5 are not required -->
4142
org.junit.*;resolution:=optional,
4243
org.hamcrest.*;resolution:=optional,
@@ -48,6 +49,7 @@
4849
<bnd-extra-module-options>
4950
<!-- Non-transitive static modules -->
5051
junit;transitive=false,
52+
org.assertj.core;transitive=false,
5153
org.hamcrest;transitive=false,
5254
org.junit.jupiter.api;transitive=false,
5355
org.junitpioneer;transitive=false,
@@ -72,6 +74,10 @@
7274
<groupId>org.apache.logging.log4j</groupId>
7375
<artifactId>log4j-api</artifactId>
7476
</dependency>
77+
<dependency>
78+
<groupId>org.assertj</groupId>
79+
<artifactId>assertj-core</artifactId>
80+
</dependency>
7581
<dependency>
7682
<groupId>org.apache.commons</groupId>
7783
<artifactId>commons-lang3</artifactId>
@@ -108,11 +114,6 @@
108114
<groupId>org.codehaus.plexus</groupId>
109115
<artifactId>plexus-utils</artifactId>
110116
</dependency>
111-
<dependency>
112-
<groupId>org.assertj</groupId>
113-
<artifactId>assertj-core</artifactId>
114-
<scope>test</scope>
115-
</dependency>
116117
<!-- Required for JSON support -->
117118
<dependency>
118119
<groupId>com.fasterxml.jackson.core</groupId>

log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.ByteArrayOutputStream;
2121
import java.io.PrintStream;
2222
import java.util.ArrayList;
23+
import java.util.HashMap;
2324
import java.util.List;
2425
import java.util.Map;
2526
import org.apache.logging.log4j.Level;
@@ -28,6 +29,7 @@
2829
import org.apache.logging.log4j.message.Message;
2930
import org.apache.logging.log4j.message.MessageFactory;
3031
import org.apache.logging.log4j.spi.AbstractLogger;
32+
import org.apache.logging.log4j.util.ProviderUtil;
3133

3234
/**
3335
*
@@ -79,7 +81,12 @@ protected void log(
7981
sb.append(' ');
8082
}
8183
sb.append(message.getFormattedMessage());
82-
final Map<String, String> mdc = ThreadContext.getImmutableContext();
84+
final Map<String, ?> contextMap =
85+
ProviderUtil.getProvider().getScopedContextProvider().getContextMap();
86+
final Map<String, String> mdc = new HashMap<>(ThreadContext.getImmutableContext());
87+
if (contextMap != null && !contextMap.isEmpty()) {
88+
contextMap.forEach((key, value) -> mdc.put(key, value.toString()));
89+
}
8390
if (!mdc.isEmpty()) {
8491
sb.append(' ');
8592
sb.append(mdc);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.test.spi;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
21+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
22+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
23+
import static org.junit.jupiter.api.Assertions.assertTrue;
24+
25+
import java.util.concurrent.ArrayBlockingQueue;
26+
import java.util.concurrent.BlockingQueue;
27+
import java.util.concurrent.Callable;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.Future;
30+
import java.util.concurrent.ThreadPoolExecutor;
31+
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.atomic.AtomicBoolean;
33+
import java.util.concurrent.atomic.AtomicInteger;
34+
import java.util.concurrent.atomic.AtomicLong;
35+
import org.apache.logging.log4j.ScopedContext;
36+
import org.apache.logging.log4j.spi.ScopedContextProvider;
37+
38+
/**
39+
* Provides test that should be passed by all implementations of {@link ScopedContextProviderSuite}.
40+
* @since 2.24.0
41+
*/
42+
public abstract class ScopedContextProviderSuite {
43+
44+
private static ScopedContext.Instance where(
45+
final ScopedContextProvider provider, final String key, final Object value) {
46+
return provider.newScopedContext(key, value);
47+
}
48+
49+
protected static void testScope(final ScopedContextProvider scopedContext) {
50+
where(scopedContext, "key1", "Log4j2")
51+
.run(() -> assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2"));
52+
where(scopedContext, "key1", "value1").run(() -> {
53+
assertThat(scopedContext.getValue("key1")).isEqualTo("value1");
54+
where(scopedContext, "key2", "value2").run(() -> {
55+
assertThat(scopedContext.getValue("key1")).isEqualTo("value1");
56+
assertThat(scopedContext.getValue("key2")).isEqualTo("value2");
57+
});
58+
});
59+
}
60+
61+
private static void runWhere(
62+
final ScopedContextProvider provider, final String key, final Object value, final Runnable task) {
63+
provider.newScopedContext(key, value).run(task);
64+
}
65+
66+
private static Future<Void> runWhere(
67+
final ScopedContextProvider provider,
68+
final String key,
69+
final Object value,
70+
final ExecutorService executorService,
71+
final Runnable task) {
72+
return provider.newScopedContext(key, value).run(executorService, task);
73+
}
74+
75+
protected static void testRunWhere(final ScopedContextProvider scopedContext) {
76+
runWhere(scopedContext, "key1", "Log4j2", () -> assertThat(scopedContext.getValue("key1"))
77+
.isEqualTo("Log4j2"));
78+
runWhere(scopedContext, "key1", "value1", () -> {
79+
assertThat(scopedContext.getValue("key1")).isEqualTo("value1");
80+
runWhere(scopedContext, "key2", "value2", () -> {
81+
assertThat(scopedContext.getValue("key1")).isEqualTo("value1");
82+
assertThat(scopedContext.getValue("key2")).isEqualTo("value2");
83+
});
84+
});
85+
}
86+
87+
protected static void testRunThreads(final ScopedContextProvider scopedContext) {
88+
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
89+
ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, workQueue);
90+
final long id = Thread.currentThread().getId();
91+
final AtomicLong counter = new AtomicLong(0);
92+
runWhere(scopedContext, "key1", "Log4j2", () -> {
93+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
94+
Future<?> future = runWhere(scopedContext, "key2", "value2", executorService, () -> {
95+
assertNotEquals(Thread.currentThread().getId(), id);
96+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
97+
counter.incrementAndGet();
98+
});
99+
assertDoesNotThrow(() -> {
100+
future.get();
101+
assertTrue(future.isDone());
102+
assertThat(counter.get()).isEqualTo(1);
103+
});
104+
});
105+
}
106+
107+
protected static void testThreads(final ScopedContextProvider scopedContext) throws Exception {
108+
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
109+
ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, workQueue);
110+
final long id = Thread.currentThread().getId();
111+
final AtomicLong counter = new AtomicLong(0);
112+
where(scopedContext, "key1", "Log4j2").run(() -> {
113+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
114+
Future<?> future = where(scopedContext, "key2", "value2").run(executorService, () -> {
115+
assertNotEquals(Thread.currentThread().getId(), id);
116+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
117+
counter.incrementAndGet();
118+
});
119+
assertDoesNotThrow(() -> {
120+
future.get();
121+
assertTrue(future.isDone());
122+
assertThat(counter.get()).isEqualTo(1);
123+
});
124+
});
125+
}
126+
127+
protected static void testThreadException(final ScopedContextProvider scopedContext) throws Exception {
128+
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
129+
final AtomicBoolean exceptionCaught = new AtomicBoolean(false);
130+
ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, workQueue);
131+
long id = Thread.currentThread().getId();
132+
runWhere(scopedContext, "key1", "Log4j2", () -> {
133+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
134+
Future<?> future = where(scopedContext, "key2", "value2").run(executorService, () -> {
135+
assertNotEquals(Thread.currentThread().getId(), id);
136+
throw new NullPointerException("On purpose NPE");
137+
});
138+
assertThatThrownBy(future::get)
139+
.hasRootCauseInstanceOf(NullPointerException.class)
140+
.hasRootCauseMessage("On purpose NPE");
141+
});
142+
}
143+
144+
private static <R> R callWhere(
145+
final ScopedContextProvider provider, final String key, final Object value, final Callable<R> task)
146+
throws Exception {
147+
return provider.newScopedContext(key, value).call(task);
148+
}
149+
150+
private static <R> Future<R> callWhere(
151+
final ScopedContextProvider provider,
152+
final String key,
153+
final Object value,
154+
final ExecutorService executorService,
155+
final Callable<R> task) {
156+
return provider.newScopedContext(key, value).call(executorService, task);
157+
}
158+
159+
protected static void testThreadCall(final ScopedContextProvider scopedContext) throws Exception {
160+
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
161+
ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, workQueue);
162+
final long id = Thread.currentThread().getId();
163+
final AtomicInteger counter = new AtomicInteger(0);
164+
int returnVal = callWhere(scopedContext, "key1", "Log4j2", () -> {
165+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
166+
Future<Integer> future = callWhere(scopedContext, "key2", "value2", executorService, () -> {
167+
assertNotEquals(Thread.currentThread().getId(), id);
168+
assertThat(scopedContext.getValue("key1")).isEqualTo("Log4j2");
169+
return counter.incrementAndGet();
170+
});
171+
Integer val = future.get();
172+
assertTrue(future.isDone());
173+
assertThat(counter.get()).isEqualTo(1);
174+
return val;
175+
});
176+
assertThat(returnVal).isEqualTo(1);
177+
}
178+
}

0 commit comments

Comments
 (0)