Sitelet https://github.com/qos-ch/logback/commit/0370b137a47a6148c3f2d527f6bfdbd22d3136a8
Skip to content

Commit 0370b13

Browse files
committed
fix missing MDC transmission in SocketAppender. Fixes issues/1010
Signed-off-by: ceki <ceki@qos.ch>
1 parent 8100acd commit 0370b13

6 files changed

Lines changed: 196 additions & 56 deletions

File tree

‎logback-classic/src/main/java/ch/qos/logback/classic/net/LoggingEventPreSerializationTransformer.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public Serializable transform(ILoggingEvent event) {
2626
if (event == null) {
2727
return null;
2828
}
29+
// Note that preprocessing is presumed to be already done
2930
if (event instanceof LoggingEvent) {
3031
return LoggingEventVO.build(event);
3132
} else if (event instanceof LoggingEventVO) {

‎logback-classic/src/main/java/ch/qos/logback/classic/net/SimpleSocketServer.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ protected static void doMain(Class<? extends SimpleSocketServer> serverClass, St
7777
configureLC(lc, configFile);
7878

7979
SimpleSocketServer sss = new SimpleSocketServer(lc, port);
80+
81+
// start the server in a separate thread
8082
sss.start();
8183
}
8284

‎logback-classic/src/main/java/ch/qos/logback/classic/net/server/ServerSocketAppender.java‎

Lines changed: 0 additions & 54 deletions
This file was deleted.

‎logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEvent.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,11 @@ public Map<String, String> getMDCPropertyMap() {
454454
// populate mdcPropertyMap if null
455455
if (mdcPropertyMap == null) {
456456
MDCAdapter mdcAdapter = loggerContext.getMDCAdapter();
457-
if (mdcAdapter instanceof LogbackMDCAdapter)
457+
if (mdcAdapter instanceof LogbackMDCAdapter) {
458458
mdcPropertyMap = ((LogbackMDCAdapter) mdcAdapter).getPropertyMap();
459-
else
459+
} else {
460460
mdcPropertyMap = mdcAdapter.getCopyOfContextMap();
461+
}
461462
}
462463
// mdcPropertyMap still null, use emptyMap()
463464
if (mdcPropertyMap == null)
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Logback: the reliable, generic, fast and flexible logging framework.
3+
* Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4+
*
5+
* This program and the accompanying materials are dual-licensed under
6+
* either the terms of the Eclipse Public License v2.0 as published by
7+
* the Eclipse Foundation
8+
*
9+
* or (per the licensee's choosing)
10+
*
11+
* under the terms of the GNU Lesser General Public License version 2.1
12+
* as published by the Free Software Foundation.
13+
*/
14+
15+
package ch.qos.logback.classic.issue.github1010;
16+
17+
import ch.qos.logback.classic.Level;
18+
import ch.qos.logback.classic.Logger;
19+
import ch.qos.logback.classic.LoggerContext;
20+
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
21+
import ch.qos.logback.classic.net.SimpleSocketServer;
22+
import ch.qos.logback.classic.net.SocketAppender;
23+
import ch.qos.logback.classic.spi.ILoggingEvent;
24+
import ch.qos.logback.classic.spi.LoggingEvent;
25+
import ch.qos.logback.classic.spi.LoggingEventVO;
26+
import ch.qos.logback.classic.util.LogbackMDCAdapter;
27+
import ch.qos.logback.core.ConsoleAppender;
28+
import ch.qos.logback.core.read.ListAppender;
29+
import ch.qos.logback.core.status.OnConsoleStatusListener;
30+
import ch.qos.logback.core.status.Status;
31+
import ch.qos.logback.core.status.StatusManager;
32+
import ch.qos.logback.core.testUtil.RandomUtil;
33+
import ch.qos.logback.core.util.StatusListenerConfigHelper;
34+
import org.junit.jupiter.api.Test;
35+
import org.junit.jupiter.api.Timeout;
36+
37+
import java.util.List;
38+
import java.util.Map;
39+
import java.util.function.Predicate;
40+
41+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
42+
import static java.util.concurrent.TimeUnit.SECONDS;
43+
import static org.junit.jupiter.api.Assertions.assertEquals;
44+
import static org.junit.jupiter.api.Assertions.assertNotNull;
45+
import static org.junit.jupiter.api.Assertions.assertTrue;
46+
import static org.junit.jupiter.api.Assertions.fail;
47+
48+
public class SocketAppender1010Test {
49+
50+
51+
private static final String HOST = "localhost";
52+
private final int port = RandomUtil.getRandomServerPort();
53+
private final String mdcKey = "moo" + RandomUtil.getPositiveInt();
54+
private final String mdcVal = "mdcVal" + RandomUtil.getPositiveInt();
55+
static final String LIST_APPENDER = "LIST_APPENDER";
56+
57+
58+
LogbackMDCAdapter mdcAdapterForClient = new LogbackMDCAdapter();
59+
60+
@Test
61+
@Timeout(value = 500, unit = MILLISECONDS)
62+
public void smoke() {
63+
System.out.println("Running on port " + port);
64+
LoggerContext serverLoggerContext = buildAndConfigureContextForServer();
65+
SimpleSocketServer simpleSocketServer = new SimpleSocketServer(serverLoggerContext, port);
66+
simpleSocketServer.start();
67+
68+
// wait until server is up
69+
yieldLoop(Thread::isAlive, simpleSocketServer);
70+
71+
LoggerContext clientLoggerContext = buildAndConfigureContextForClient(mdcAdapterForClient);
72+
Logger clientLogger = clientLoggerContext.getLogger(SocketAppender1010Test.class);
73+
Logger serverRoot = serverLoggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
74+
mdcAdapterForClient.put(mdcKey, mdcVal);
75+
clientLogger.info("hello");
76+
77+
StatusManager clientStatusManager = clientLoggerContext.getStatusManager();
78+
79+
// wait until connection is established
80+
yieldLoop(csm -> csm.getCopyOfStatusList().stream().anyMatch(s -> s.getMessage().contains("connection established")), clientStatusManager);
81+
82+
ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) serverRoot.getAppender(LIST_APPENDER);
83+
assertNotNull(listAppender);
84+
assertNotNull(listAppender.list);
85+
yieldLoop(( list -> !list.isEmpty()), listAppender.list);
86+
87+
88+
assertEquals(1, listAppender.list.size());
89+
ILoggingEvent loggingEvent = listAppender.list.get(0);
90+
assertNotNull(loggingEvent);
91+
assertTrue(loggingEvent instanceof LoggingEventVO);
92+
LoggingEventVO loggingEventVO = (LoggingEventVO) loggingEvent;
93+
Map<String, String> mdcMap = loggingEventVO.getMdc();
94+
assertNotNull(mdcMap);
95+
assertEquals(mdcVal, mdcMap.get(mdcKey));
96+
97+
}
98+
99+
100+
<T> void yieldLoop(Predicate<T> predicate, T arg) {
101+
while(true) {
102+
if(predicate.test(arg)) {
103+
break;
104+
}
105+
Thread.yield();
106+
}
107+
}
108+
109+
private static void sleep(int millis) {
110+
try {
111+
Thread.sleep(millis);
112+
} catch (InterruptedException e) {
113+
throw new RuntimeException(e);
114+
}
115+
}
116+
117+
LoggerContext buildAndConfigureContextForServer() {
118+
LoggerContext context = new LoggerContext();
119+
context.setName("serverContext");
120+
LogbackMDCAdapter mdcAdapter = new LogbackMDCAdapter();
121+
context.setMDCAdapter(mdcAdapter);
122+
123+
StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
124+
125+
Logger root = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
126+
root.setLevel(Level.DEBUG);
127+
128+
129+
ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
130+
listAppender.setName(LIST_APPENDER);
131+
listAppender.setContext(context);
132+
listAppender.start();
133+
root.addAppender(listAppender);
134+
135+
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
136+
consoleAppender.setContext(context);
137+
consoleAppender.setName("STDOUT");
138+
139+
// PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
140+
// patternLayoutEncoder.setContext(context);
141+
// patternLayoutEncoder.setPattern("%-4relative [%thread] %level %logger{35} =%mdc= -%kvp- %msg %n");
142+
// patternLayoutEncoder.setParent(consoleAppender);
143+
// patternLayoutEncoder.start();
144+
// consoleAppender.setEncoder(patternLayoutEncoder);
145+
// consoleAppender.start();
146+
// root.addAppender(consoleAppender);
147+
148+
return context;
149+
}
150+
151+
152+
LoggerContext buildAndConfigureContextForClient(LogbackMDCAdapter mdcAdapter) {
153+
LoggerContext context = new LoggerContext();
154+
context.setName("clientContext");
155+
156+
context.setMDCAdapter(mdcAdapter);
157+
158+
StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
159+
160+
SocketAppender socketAppender = buildSocketAppender(context);
161+
162+
Logger root = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
163+
root.setLevel(Level.DEBUG);
164+
root.addAppender(socketAppender);
165+
166+
return context;
167+
}
168+
169+
170+
SocketAppender buildSocketAppender(LoggerContext context) {
171+
SocketAppender socketAppender = new SocketAppender();
172+
socketAppender.setContext(context);
173+
socketAppender.setName("socketAppender");
174+
socketAppender.setRemoteHost(HOST);
175+
socketAppender.setPort(port);
176+
socketAppender.setReconnectionDelay(ch.qos.logback.core.util.Duration.valueOf("100"));
177+
socketAppender.setIncludeCallerData(true);
178+
179+
socketAppender.start();
180+
return socketAppender;
181+
}
182+
183+
}

‎logback-core/src/main/java/ch/qos/logback/core/net/AbstractSocketAppender.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import javax.net.SocketFactory;
2828

2929
import ch.qos.logback.core.AppenderBase;
30+
import ch.qos.logback.core.spi.DeferredProcessingAware;
3031
import ch.qos.logback.core.spi.PreSerializationTransformer;
3132
import ch.qos.logback.core.util.CloseUtil;
3233
import ch.qos.logback.core.util.Duration;
@@ -176,6 +177,12 @@ protected void append(E event) {
176177
return;
177178

178179
try {
180+
181+
// otherwise MDC information is not transferred. See also logback/issues/1010
182+
if(event instanceof DeferredProcessingAware) {
183+
((DeferredProcessingAware) event).prepareForDeferredProcessing();
184+
}
185+
179186
final boolean inserted = deque.offer(event, eventDelayLimit.getMilliseconds(), TimeUnit.MILLISECONDS);
180187
if (!inserted) {
181188
addInfo("Dropping event due to timeout limit of [" + eventDelayLimit + "] being exceeded");

0 commit comments

Comments
 (0)