Skip to content

Commit aa7d584

Browse files
committed
MDC values no longer inherited. This fixes LOGBACK-422 and LOGBACK-624
1 parent 1af14db commit aa7d584

3 files changed

Lines changed: 48 additions & 23 deletions

File tree

logback-classic/src/main/java/ch/qos/logback/classic/util/LogbackMDCAdapter.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313
*/
1414
package ch.qos.logback.classic.util;
1515

16+
import java.util.Collections;
1617
import java.util.HashMap;
1718
import java.util.Map;
18-
import java.util.Collections;
1919
import java.util.Set;
2020

21-
2221
import org.slf4j.spi.MDCAdapter;
2322

2423
/**
@@ -53,7 +52,7 @@ public class LogbackMDCAdapter implements MDCAdapter {
5352
// Initially the contents of the thread local in parent and child threads
5453
// reference the same map. However, as soon as a thread invokes the put()
5554
// method, the maps diverge as they should.
56-
final InheritableThreadLocal<Map<String, String>> copyOnInheritThreadLocal = new InheritableThreadLocal<Map<String, String>>();
55+
final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal<Map<String, String>>();
5756

5857
private static final int WRITE_OPERATION = 1;
5958
private static final int MAP_COPY_OPERATION = 2;
@@ -81,7 +80,7 @@ private Map<String, String> duplicateAndInsertNewMap(Map<String, String> oldMap)
8180
}
8281
}
8382

84-
copyOnInheritThreadLocal.set(newMap);
83+
copyOnThreadLocal.set(newMap);
8584
return newMap;
8685
}
8786

@@ -101,7 +100,7 @@ public void put(String key, String val) throws IllegalArgumentException {
101100
throw new IllegalArgumentException("key cannot be null");
102101
}
103102

104-
Map<String, String> oldMap = copyOnInheritThreadLocal.get();
103+
Map<String, String> oldMap = copyOnThreadLocal.get();
105104
Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);
106105

107106
if (wasLastOpReadOrNull(lastOp) || oldMap == null) {
@@ -120,7 +119,7 @@ public void remove(String key) {
120119
if (key == null) {
121120
return;
122121
}
123-
Map<String, String> oldMap = copyOnInheritThreadLocal.get();
122+
Map<String, String> oldMap = copyOnThreadLocal.get();
124123
if (oldMap == null) return;
125124

126125
Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);
@@ -139,15 +138,15 @@ public void remove(String key) {
139138
*/
140139
public void clear() {
141140
lastOperation.set(WRITE_OPERATION);
142-
copyOnInheritThreadLocal.remove();
141+
copyOnThreadLocal.remove();
143142
}
144143

145144
/**
146145
* Get the context identified by the <code>key</code> parameter.
147146
* <p/>
148147
*/
149148
public String get(String key) {
150-
final Map<String, String> map = copyOnInheritThreadLocal.get();
149+
final Map<String, String> map = copyOnThreadLocal.get();
151150
if ((map != null) && (key != null)) {
152151
return map.get(key);
153152
} else {
@@ -161,7 +160,7 @@ public String get(String key) {
161160
*/
162161
public Map<String, String> getPropertyMap() {
163162
lastOperation.set(MAP_COPY_OPERATION);
164-
return copyOnInheritThreadLocal.get();
163+
return copyOnThreadLocal.get();
165164
}
166165

167166
/**
@@ -183,7 +182,7 @@ public Set<String> getKeys() {
183182
* null.
184183
*/
185184
public Map<String, String> getCopyOfContextMap() {
186-
Map<String, String> hashMap = copyOnInheritThreadLocal.get();
185+
Map<String, String> hashMap = copyOnThreadLocal.get();
187186
if (hashMap == null) {
188187
return null;
189188
} else {
@@ -198,6 +197,6 @@ public void setContextMap(Map<String, String> contextMap) {
198197
newMap.putAll(contextMap);
199198

200199
// the newMap replaces the old one for serialisation's sake
201-
copyOnInheritThreadLocal.set(newMap);
200+
copyOnThreadLocal.set(newMap);
202201
}
203202
}

logback-classic/src/test/java/ch/qos/logback/classic/util/LogbackMDCAdapterTest.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public class LogbackMDCAdapterTest {
3535

3636
private final LogbackMDCAdapter mdcAdapter = new LogbackMDCAdapter();
3737

38-
3938
/**
4039
* Test that CopyOnInheritThreadLocal does not barf when the
4140
* MDC hashmap is null
@@ -67,12 +66,12 @@ public void removeInexistentKey() {
6766
@Test
6867
public void sequenceWithGet() {
6968
mdcAdapter.put("k0", "v0");
70-
Map<String, String> map0 = mdcAdapter.copyOnInheritThreadLocal.get();
69+
Map<String, String> map0 = mdcAdapter.copyOnThreadLocal.get();
7170
mdcAdapter.get("k0");
7271
mdcAdapter.put("k1", "v1"); // no map copy required
7372

7473
// verify that map0 is the same instance and that value was updated
75-
assertSame(map0, mdcAdapter.copyOnInheritThreadLocal.get());
74+
assertSame(map0, mdcAdapter.copyOnThreadLocal.get());
7675
}
7776

7877

@@ -88,25 +87,25 @@ public void sequenceWithGetPropertyMap() {
8887
@Test
8988
public void sequenceWithCopyContextMap() {
9089
mdcAdapter.put("k0", "v0");
91-
Map<String, String> map0 = mdcAdapter.copyOnInheritThreadLocal.get();
90+
Map<String, String> map0 = mdcAdapter.copyOnThreadLocal.get();
9291
mdcAdapter.getCopyOfContextMap();
9392
mdcAdapter.put("k1", "v1"); // no map copy required
9493

9594
// verify that map0 is the same instance and that value was updated
96-
assertSame(map0, mdcAdapter.copyOnInheritThreadLocal.get());
95+
assertSame(map0, mdcAdapter.copyOnThreadLocal.get());
9796
}
9897

9998

10099
// =================================================
101100

102101
/**
103-
* Test that LogbackMDCAdapter copies its hashmap when a child
102+
* Test that LogbackMDCAdapter does not copy its hashmap when a child
104103
* thread inherits it.
105104
*
106105
* @throws InterruptedException
107106
*/
108107
@Test
109-
public void copyOnInheritenceTest() throws InterruptedException {
108+
public void noCopyOnInheritenceTest() throws InterruptedException {
110109
CountDownLatch countDownLatch = new CountDownLatch(1);
111110
String firstKey = "x" + diff;
112111
String secondKey = "o" + diff;
@@ -129,7 +128,6 @@ public void copyOnInheritenceTest() throws InterruptedException {
129128
assertEquals(parentHMWitness, parentHM);
130129

131130
HashMap<String, String> childHMWitness = new HashMap<String, String>();
132-
childHMWitness.put(firstKey, firstKey + A_SUFFIX);
133131
childHMWitness.put(secondKey, secondKey + A_SUFFIX);
134132
assertEquals(childHMWitness, childThread.childHM);
135133

@@ -195,8 +193,8 @@ public void run() {
195193

196194

197195
Map<String, String> getMapFromMDCAdapter(LogbackMDCAdapter lma) {
198-
InheritableThreadLocal<Map<String, String>> copyOnInheritThreadLocal = lma.copyOnInheritThreadLocal;
199-
return copyOnInheritThreadLocal.get();
196+
ThreadLocal<Map<String, String>> copyOnThreadLocal = lma.copyOnThreadLocal;
197+
return copyOnThreadLocal.get();
200198
}
201199

202200
// ========================== various thread classes
@@ -247,10 +245,11 @@ class ChildThread extends Thread {
247245
@Override
248246
public void run() {
249247
logbackMDCAdapter.put(secondKey, secondKey + A_SUFFIX);
250-
assertNotNull(logbackMDCAdapter.get(firstKey));
251-
assertEquals(firstKey + A_SUFFIX, logbackMDCAdapter.get(firstKey));
248+
assertNull(logbackMDCAdapter.get(firstKey));
252249
if (countDownLatch != null) countDownLatch.countDown();
250+
assertNotNull(logbackMDCAdapter.get(secondKey));
253251
assertEquals(secondKey + A_SUFFIX, logbackMDCAdapter.get(secondKey));
252+
254253
successful = true;
255254
childHM = getMapFromMDCAdapter(logbackMDCAdapter);
256255
}

logback-site/src/site/pages/news.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,33 @@ <h2>Logback News</h2>
3232
<h3>2016, Release of version 1.1.5</h3>
3333

3434

35+
<div class="breaking">
36+
<h4>MDC values are no longer inherited by child threads.</h4>
37+
</div>
38+
39+
<p>Child threads no longer inherit MDC values. In previous
40+
versions of logback as well as log4j 1.x, MDC values were
41+
inherited by child threads. Several users have argued convincingly
42+
that MDC inheritance by child threads was unhelpful and even
43+
dangerous. This change fixes <a
44+
href="http://jira.qos.ch/browse/LOGBACK-422">LOGBACK-422</a> and <a
45+
href="http://jira.qos.ch/browse/LOGBACK-624">LOGBACK-624</a>
46+
</p>
47+
48+
<p>When the <code>FileNamePattern</code> string for
49+
<code>RollingFileAppender/SizeAndTimeBasedFNATP</code> lacks a %i
50+
token, then compression for the second archive in the same period
51+
cannot occur as the target file already exists. Under those
52+
circumstances, logback leaves behind .tmp files as reported in <a
53+
href="http://jira.qos.ch/browse/LOGBACK-992">LOGBACK-992</a>, <a
54+
href="http://jira.qos.ch/browse/LOGBACK-173">LOGBACK-173</a> and
55+
<a
56+
href="http://jira.qos.ch/browse/LOGBACK-920">LOGBACK-920</a>. In
57+
this release, this particular condition is detected by
58+
<code>RollingFileAppender</code> which will not start but alert
59+
the user instead.
60+
</p>
61+
3562
<p>AsyncAppender is now configurable to never block. This feature
3663
was requested by Jeff Wartes in <a
3764
href="http://jira.qos.ch/browse/LOGBACK-898">LOGBACK-898</a> with

0 commit comments

Comments
 (0)