1
2
3
4
5
6
7
8
9
10
11
12
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 = 2000, 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
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
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
140
141
142
143
144
145
146
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 }