Skip to content

Commit 05fba96

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

File tree

5 files changed

+377
-1
lines changed

5 files changed

+377
-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-log4j12/src/test/java/org/slf4j/log4j12/InvocationTest.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,112 @@ public void testMDCContextMapValues() {
188188
assertEquals("vb", MDC.get("kb"));
189189
}
190190

191+
@Test
192+
public void testMDCPutAll() {
193+
Map<String, String> values = new HashMap<>();
194+
values.put("k1", "v1");
195+
values.put("k2", "v2");
196+
197+
MDC.put("k", "v");
198+
MDC.putAll(values);
199+
200+
assertNotNull(MDC.get("k"));
201+
assertNotNull(MDC.get("k1"));
202+
assertNotNull(MDC.get("k2"));
203+
MDC.remove("k1");
204+
MDC.remove("k2");
205+
assertNotNull(MDC.get("k"));
206+
assertNull(MDC.get("k1"));
207+
assertNull(MDC.get("k2"));
208+
MDC.clear();
209+
}
210+
211+
@Test
212+
public void testMDCCloseable() {
213+
MDC.put("pre", "v");
214+
try(MDC.MDCCloseable mdcCloseable = MDC.putCloseable("try-with", "v")) {
215+
assertNotNull(MDC.get("pre"));
216+
assertNotNull(MDC.get("try-with"));
217+
assertNull(MDC.get("post"));
218+
}
219+
MDC.put("post", "v");
220+
assertNotNull(MDC.get("pre"));
221+
assertNull(MDC.get("try-with"));
222+
assertNotNull(MDC.get("post"));
223+
MDC.clear();
224+
}
225+
226+
@Test
227+
public void testMDCCloseableOverwrites() {
228+
MDC.put("pre", "v");
229+
try(MDC.MDCCloseable mdcCloseable = MDC.putCloseable("pre", "v2")) {
230+
assertNotNull(MDC.get("pre"));
231+
assertEquals("v2", MDC.get("pre"));
232+
assertNull(MDC.get("post"));
233+
}
234+
MDC.put("post", "v");
235+
assertNull(MDC.get("pre"));
236+
assertNotNull(MDC.get("post"));
237+
MDC.clear();
238+
}
239+
240+
@Test
241+
public void testMDCCloseablePutAllImmutable() {
242+
Map<String, String> values = new HashMap<>();
243+
values.put("try-with", "v");
244+
245+
MDC.put("pre", "v");
246+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
247+
values.remove("try-with");
248+
assertNotNull(MDC.get("pre"));
249+
assertNotNull(MDC.get("try-with"));
250+
assertNull(MDC.get("post"));
251+
}
252+
MDC.put("post", "v");
253+
assertNotNull(MDC.get("pre"));
254+
assertNull(MDC.get("try-with"));
255+
assertNotNull(MDC.get("post"));
256+
MDC.clear();
257+
}
258+
259+
@Test
260+
public void testMDCCloseablePutAll() {
261+
Map<String, String> values = new HashMap<>();
262+
values.put("try-with", "v");
263+
264+
MDC.put("pre", "v");
265+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
266+
assertNotNull(MDC.get("pre"));
267+
assertNotNull(MDC.get("try-with"));
268+
assertNull(MDC.get("post"));
269+
}
270+
MDC.put("post", "v");
271+
assertNotNull(MDC.get("pre"));
272+
assertNull(MDC.get("try-with"));
273+
assertNotNull(MDC.get("post"));
274+
MDC.clear();
275+
}
276+
277+
@Test
278+
public void testMDCCloseablePutAllOverwrites() {
279+
Map<String, String> values = new HashMap<>();
280+
values.put("pre", "v2");
281+
values.put("try-with", "v");
282+
283+
MDC.put("pre", "v");
284+
try(MDC.MDCCloseable mdcCloseable = MDC.putAllCloseable(values)) {
285+
assertNotNull(MDC.get("pre"));
286+
assertEquals("v2", MDC.get("pre"));
287+
assertNotNull(MDC.get("try-with"));
288+
assertNull(MDC.get("post"));
289+
}
290+
MDC.put("post", "v");
291+
assertNull(MDC.get("pre"));
292+
assertNull(MDC.get("try-with"));
293+
assertNotNull(MDC.get("post"));
294+
MDC.clear();
295+
}
296+
191297
@Test
192298
public void testCallerInfo() {
193299
Logger logger = LoggerFactory.getLogger("testMarker");

0 commit comments

Comments
 (0)