Skip to content

Commit 999001e

Browse files
committed
implement putAll and putAllCloseable - SLF4J-387
Implements putAll and putAllCloseable described in SLF4J-387 Signed-off-by: Nikolas Grottendieck <[email protected]>
1 parent aa0de34 commit 999001e

File tree

5 files changed

+376
-1
lines changed

5 files changed

+376
-1
lines changed

slf4j-api/src/main/java/org/slf4j/MDC.java

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626

2727
import java.io.Closeable;
2828
import java.util.Deque;
29+
import java.util.HashSet;
2930
import java.util.Map;
31+
import java.util.Set;
3032

3133
import org.slf4j.helpers.BasicMDCAdapter;
3234
import org.slf4j.helpers.NOPMDCAdapter;
@@ -74,13 +76,25 @@ public class MDC {
7476
*/
7577
public static class MDCCloseable implements Closeable {
7678
private final String key;
79+
private final Set<String> keys;
7780

7881
private MDCCloseable(String key) {
7982
this.key = key;
83+
this.keys = null;
84+
}
85+
86+
private MDCCloseable(Set<String> keys) {
87+
this.key = null;
88+
this.keys = new HashSet<>(keys);
8089
}
8190

8291
public void close() {
83-
MDC.remove(this.key);
92+
if (this.key != null) {
93+
MDC.remove(this.key);
94+
}
95+
if (this.keys != null) {
96+
this.keys.forEach(MDC::remove);
97+
}
8498
}
8599
}
86100

@@ -123,6 +137,32 @@ public static void put(String key, String val) throws IllegalArgumentException {
123137
mdcAdapter.put(key, val);
124138
}
125139

140+
/**
141+
* Put a diagnostic context map (the <code>entries</code> parameter) as identified with each
142+
* <code>key</code> into the current thread's diagnostic context map. The
143+
* <code>entries</code> parameter and its <code>keys</code> cannot be null. The
144+
* <code>value</code> of each entry can be null only if the underlying implementation
145+
* supports it.
146+
*
147+
* <p>
148+
* This method delegates all work to the MDC of the underlying logging system.
149+
*
150+
* @param entries entries to put in the map
151+
*
152+
* @throws IllegalArgumentException
153+
* in case the "entries" parameter is null
154+
* @since 2.0.0
155+
*/
156+
public static void putAll(Map<String, String> entries) throws IllegalArgumentException {
157+
if (entries == null) {
158+
throw new IllegalArgumentException("entries parameter cannot be null");
159+
}
160+
if (mdcAdapter == null) {
161+
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
162+
}
163+
entries.forEach((k,v) -> mdcAdapter.put(k, v));
164+
}
165+
126166
/**
127167
* Put a diagnostic context value (the <code>val</code> parameter) as identified with the
128168
* <code>key</code> parameter into the current thread's diagnostic context map. The
@@ -156,6 +196,40 @@ public static MDCCloseable putCloseable(String key, String val) throws IllegalAr
156196
return new MDCCloseable(key);
157197
}
158198

199+
/**
200+
* Put a diagnostic context map (the <code>entries</code> parameter) as identified with each
201+
* <code>key</code> into the current thread's diagnostic context map. The
202+
* <code>entries</code> parameter and its <code>keys</code> cannot be null. The
203+
* <code>value</code> of each entry can be null only if the underlying implementation
204+
* supports it.
205+
*
206+
* <p>
207+
* This method delegates all work to the MDC of the underlying logging system.
208+
* <p>
209+
* This method returns a <code>Closeable</code> object which can remove all <code>keys</code>
210+
* that are part of the <code>entries</code> when <code>close</code> is called.
211+
*
212+
* <p>
213+
* Useful with Java 9 for example :
214+
* <code>
215+
* try(MDC.MDCCloseable closeable = MDC.putAllCloseable(Map.of(key1, value, key2, value2)) {
216+
* ....
217+
* }
218+
* </code>
219+
*
220+
* @param entries entries to put in the map
221+
* @return a <code>Closeable</code> who can remove all originally supplied <code>keys</code>
222+
* when <code>close</code> is called.
223+
*
224+
* @throws IllegalArgumentException
225+
* in case the "entries" parameter is null
226+
* @since 2.0.0
227+
*/
228+
public static MDCCloseable putAllCloseable(Map<String, String> entries) throws IllegalArgumentException {
229+
MDC.putAll(entries);
230+
return new MDCCloseable(entries.keySet());
231+
}
232+
159233
/**
160234
* Get the diagnostic context identified by the <code>key</code> parameter. The
161235
* <code>key</code> parameter cannot be null.

slf4j-jdk14/src/test/java/org/slf4j/jul/InvocationTest.java

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.junit.Test;
3131
import org.slf4j.*;
3232

33+
import java.util.HashMap;
34+
import java.util.Map;
3335
import java.util.logging.Handler;
3436
import java.util.logging.Level;
3537
import java.util.logging.LogRecord;
@@ -170,6 +172,127 @@ public void testMDC() {
170172
}
171173
}
172174

175+
@Test
176+
public void testMDCContextMapValues() {
177+
Map<String, String> map = new HashMap<>();
178+
map.put("ka", "va");
179+
map.put("kb", "vb");
180+
181+
MDC.put("k", "v");
182+
assertEquals("v", MDC.get("k"));
183+
MDC.setContextMap(map);
184+
assertNull(MDC.get("k"));
185+
assertEquals("va", MDC.get("ka"));
186+
assertEquals("vb", MDC.get("kb"));
187+
}
188+
189+
190+
@Test
191+
public void testMDCPutAll() {
192+
Map<String, String> values = new HashMap<>();
193+
values.put("k1", "v1");
194+
values.put("k2", "v2");
195+
196+
MDC.put("k", "v");
197+
MDC.putAll(values);
198+
199+
assertNotNull(MDC.get("k"));
200+
assertNotNull(MDC.get("k1"));
201+
assertNotNull(MDC.get("k2"));
202+
MDC.remove("k1");
203+
MDC.remove("k2");
204+
assertNotNull(MDC.get("k"));
205+
assertNull(MDC.get("k1"));
206+
assertNull(MDC.get("k2"));
207+
MDC.clear();
208+
}
209+
210+
@Test
211+
public void testMDCCloseable() {
212+
MDC.put("pre", "v");
213+
try(MDC.MDCCloseable mdcCloseable = MDC.putCloseable("try-with", "v")) {
214+
assertNotNull(MDC.get("pre"));
215+
assertNotNull(MDC.get("try-with"));
216+
assertNull(MDC.get("post"));
217+
}
218+
MDC.put("post", "v");
219+
assertNotNull(MDC.get("pre"));
220+
assertNull(MDC.get("try-with"));
221+
assertNotNull(MDC.get("post"));
222+
MDC.clear();
223+
}
224+
225+
@Test
226+
public void testMDCCloseableOverwrites() {
227+
MDC.put("pre", "v");
228+
try(MDC.MDCCloseable mdcCloseable = MDC.putCloseable("pre", "v2")) {
229+
assertNotNull(MDC.get("pre"));
230+
assertEquals("v2", MDC.get("pre"));
231+
assertNull(MDC.get("post"));
232+
}
233+
MDC.put("post", "v");
234+
assertNull(MDC.get("pre"));
235+
assertNotNull(MDC.get("post"));
236+
MDC.clear();
237+
}
238+
239+
@Test
240+
public void testMDCCloseablePutAll() {
241+
Map<String, String> values = new HashMap<>();
242+
values.put("try-with", "v");
243+
244+
MDC.put("pre", "v");
245+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
246+
assertNotNull(MDC.get("pre"));
247+
assertNotNull(MDC.get("try-with"));
248+
assertNull(MDC.get("post"));
249+
}
250+
MDC.put("post", "v");
251+
assertNotNull(MDC.get("pre"));
252+
assertNull(MDC.get("try-with"));
253+
assertNotNull(MDC.get("post"));
254+
MDC.clear();
255+
}
256+
257+
@Test
258+
public void testMDCCloseablePutAllOverwrites() {
259+
Map<String, String> values = new HashMap<>();
260+
values.put("pre", "v2");
261+
values.put("try-with", "v");
262+
263+
MDC.put("pre", "v");
264+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
265+
assertNotNull(MDC.get("pre"));
266+
assertEquals("v2", MDC.get("pre"));
267+
assertNotNull(MDC.get("try-with"));
268+
assertNull(MDC.get("post"));
269+
}
270+
MDC.put("post", "v");
271+
assertNull(MDC.get("pre"));
272+
assertNull(MDC.get("try-with"));
273+
assertNotNull(MDC.get("post"));
274+
MDC.clear();
275+
}
276+
277+
@Test
278+
public void testMDCCloseablePutAllImmutable() {
279+
Map<String, String> values = new HashMap<>();
280+
values.put("try-with", "v");
281+
282+
MDC.put("pre", "v");
283+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
284+
values.remove("try-with");
285+
assertNotNull(MDC.get("pre"));
286+
assertNotNull(MDC.get("try-with"));
287+
assertNull(MDC.get("post"));
288+
}
289+
MDC.put("post", "v");
290+
assertNotNull(MDC.get("pre"));
291+
assertNull(MDC.get("try-with"));
292+
assertNotNull(MDC.get("post"));
293+
MDC.clear();
294+
}
295+
173296
private void assertLogMessage(String expected, int index) {
174297
LogRecord logRecord = listHandler.recordList.get(index);
175298
Assert.assertNotNull(logRecord);

slf4j-nop/src/test/java/org/slf4j/nop/InvocationTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
import org.slf4j.Marker;
3434
import org.slf4j.MarkerFactory;
3535

36+
import java.util.HashMap;
37+
import java.util.Map;
38+
3639
/**
3740
* Test whether invoking the SLF4J API causes problems or not.
3841
*
@@ -115,6 +118,21 @@ public void testMDC() {
115118
MDC.clear();
116119
}
117120

121+
@Test
122+
public void testMDCPutAll() {
123+
Map<String, String> values = new HashMap<>();
124+
values.put("key1", "value1");
125+
values.put("key2", "value2");
126+
MDC.putAll(values);
127+
assertNull(MDC.get("key1"));
128+
assertNull(MDC.get("key2"));
129+
MDC.remove("key1");
130+
MDC.remove("key2");
131+
assertNull(MDC.get("key1"));
132+
assertNull(MDC.get("key2"));
133+
MDC.clear();
134+
}
135+
118136
@Test
119137
public void testMDCCloseable() {
120138
MDC.MDCCloseable closeable = MDC.putCloseable("k", "v");
@@ -123,4 +141,18 @@ public void testMDCCloseable() {
123141
assertNull(MDC.get("k"));
124142
MDC.clear();
125143
}
144+
145+
@Test
146+
public void testMDCCloseablePutAll() {
147+
Map<String, String> values = new HashMap<>();
148+
values.put("key1", "value1");
149+
values.put("key2", "value2");
150+
MDC.MDCCloseable closeable = MDC.putAllCloseable(values);
151+
assertNull(MDC.get("key1"));
152+
assertNull(MDC.get("key2"));
153+
closeable.close();
154+
assertNull(MDC.get("key1"));
155+
assertNull(MDC.get("key2"));
156+
MDC.clear();
157+
}
126158
}

0 commit comments

Comments
 (0)