1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.pattern;
15
16 import ch.qos.logback.classic.*;
17 import ch.qos.logback.classic.spi.ILoggingEvent;
18 import ch.qos.logback.classic.spi.LoggingEvent;
19 import ch.qos.logback.classic.util.LogbackMDCAdapter;
20 import ch.qos.logback.core.CoreConstants;
21 import ch.qos.logback.core.net.SyslogConstants;
22 import ch.qos.logback.core.pattern.DynamicConverter;
23 import ch.qos.logback.core.pattern.FormatInfo;
24 import ch.qos.logback.core.util.EnvUtil;
25 import ch.qos.logback.core.util.StatusPrinter;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.slf4j.MarkerFactory;
29
30 import java.time.Instant;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.regex.Pattern;
34
35 import static org.junit.jupiter.api.Assertions.*;
36
37 public class ConverterTest {
38
39 LoggerContext loggerContext = new LoggerContext();
40 LogbackMDCAdapter logbackMDCAdapter = new LogbackMDCAdapter();
41 Logger logger = loggerContext.getLogger(ConverterTest.class);
42 LoggingEvent le;
43
44
45
46
47
48 LoggingEvent makeLoggingEvent(Exception ex) {
49 return new LoggingEvent(ch.qos.logback.core.pattern.FormattingConverter.class.getName(), logger, Level.INFO,
50 "Some message", ex, null);
51 }
52
53 Exception getException(String msg, Exception cause) {
54 return new Exception(msg, cause);
55 }
56
57 @BeforeEach
58 public void setUp() throws Exception {
59 loggerContext.setMDCAdapter(logbackMDCAdapter);
60 Exception rootEx = getException("Innermost", null);
61 Exception nestedEx = getException("Nested", rootEx);
62
63 Exception ex = new Exception("Bogus exception", nestedEx);
64
65 le = makeLoggingEvent(ex);
66 }
67
68 @Test
69 public void testLineOfCaller() {
70 {
71 DynamicConverter<ILoggingEvent> converter = new LineOfCallerConverter();
72 StringBuilder buf = new StringBuilder();
73 converter.write(buf, le);
74
75 assertEquals("73", buf.toString());
76 }
77 }
78
79 @Test
80 public void testLevel() {
81 {
82 DynamicConverter<ILoggingEvent> converter = new LevelConverter();
83 StringBuilder buf = new StringBuilder();
84 converter.write(buf, le);
85 assertEquals("INFO", buf.toString());
86 }
87 {
88 DynamicConverter<ILoggingEvent> converter = new LevelConverter();
89 converter.setFormattingInfo(new FormatInfo(1, 1, true, false));
90 StringBuilder buf = new StringBuilder();
91 converter.write(buf, le);
92 assertEquals("I", buf.toString());
93 }
94 }
95
96 @Test
97 public void testThread() {
98 DynamicConverter<ILoggingEvent> converter = new ThreadConverter();
99 StringBuilder buf = new StringBuilder();
100 converter.write(buf, le);
101 System.out.println(buf.toString());
102 String regex = ClassicTestConstants.NAKED_MAIN_REGEX;
103 assertTrue(buf.toString().matches(regex));
104 }
105
106 @Test
107 public void testMessage() {
108 DynamicConverter<ILoggingEvent> converter = new MessageConverter();
109 StringBuilder buf = new StringBuilder();
110 converter.write(buf, le);
111 assertEquals("Some message", buf.toString());
112 }
113
114 @Test
115 public void testLineSeparator() {
116 DynamicConverter<ILoggingEvent> converter = new LineSeparatorConverter();
117 StringBuilder buf = new StringBuilder();
118 converter.write(buf, le);
119 assertEquals(CoreConstants.LINE_SEPARATOR, buf.toString());
120 }
121
122 @Test
123 public void testException() {
124 {
125 DynamicConverter<ILoggingEvent> converter = new ThrowableProxyConverter();
126 StringBuilder buf = new StringBuilder();
127 converter.write(buf, le);
128 }
129
130 {
131 DynamicConverter<ILoggingEvent> converter = new ThrowableProxyConverter();
132 converter.setOptionList(List.of("3"));
133 StringBuilder buf = new StringBuilder();
134 converter.write(buf, le);
135 }
136 }
137
138 @Test
139 public void testLogger() {
140 {
141 ClassicConverter converter = new LoggerConverter();
142 StringBuilder buf = new StringBuilder();
143 converter.write(buf, le);
144 assertEquals(this.getClass().getName(), buf.toString());
145 }
146
147 {
148 ClassicConverter converter = new LoggerConverter();
149 converter.setOptionList(List.of("20"));
150 converter.start();
151 StringBuilder buf = new StringBuilder();
152 converter.write(buf, le);
153 assertEquals("c.q.l.c.p.ConverterTest", buf.toString());
154 }
155
156 {
157 DynamicConverter<ILoggingEvent> converter = new LoggerConverter();
158 converter.setOptionList(List.of("0"));
159 converter.start();
160 StringBuilder buf = new StringBuilder();
161 converter.write(buf, le);
162 assertEquals("ConverterTest", buf.toString());
163 }
164 }
165
166 @Test
167 public void testVeryLongLoggerName() {
168 ClassicConverter converter = new LoggerConverter();
169 converter.setOptionList(List.of("5"));
170 converter.start();
171 StringBuilder buf = new StringBuilder();
172
173 char c = 'a';
174 int extraParts = 3;
175 int totalParts = ClassicConstants.MAX_DOTS + extraParts;
176 StringBuilder loggerNameBuf = new StringBuilder();
177 StringBuilder witness = new StringBuilder();
178
179 for (int i = 0; i < totalParts; i++) {
180 loggerNameBuf.append(c).append(c).append(c);
181 witness.append(c);
182 loggerNameBuf.append('.');
183 witness.append('.');
184 }
185 loggerNameBuf.append("zzzzzz");
186 witness.append("zzzzzz");
187
188 le.setLoggerName(loggerNameBuf.toString());
189 converter.write(buf, le);
190 assertEquals(witness.toString(), buf.toString());
191 }
192
193 @Test
194 public void testClass() {
195 DynamicConverter<ILoggingEvent> converter = new ClassOfCallerConverter();
196 StringBuilder buf = new StringBuilder();
197 converter.write(buf, le);
198 assertEquals(this.getClass().getName(), buf.toString());
199 }
200
201 @Test
202 public void testMethodOfCaller() {
203 DynamicConverter<ILoggingEvent> converter = new MethodOfCallerConverter();
204 StringBuilder buf = new StringBuilder();
205 converter.write(buf, le);
206 assertEquals("testMethodOfCaller", buf.toString());
207 }
208
209 @Test
210 public void testFileOfCaller() {
211 DynamicConverter<ILoggingEvent> converter = new FileOfCallerConverter();
212 StringBuilder buf = new StringBuilder();
213 converter.write(buf, le);
214 assertEquals("ConverterTest.java", buf.toString());
215 }
216
217 @Test
218 public void testCallerData() {
219 {
220 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
221 converter.start();
222
223 StringBuilder buf = new StringBuilder();
224 converter.write(buf, le);
225 if (buf.length() < 10) {
226 fail("buf is too short");
227 }
228 }
229
230 {
231 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
232 converter.setOptionList(List.of("2", "XXX"));
233 converter.start();
234
235 StringBuilder buf = new StringBuilder();
236 LoggingEvent event = makeLoggingEvent(null);
237 event.addMarker(MarkerFactory.getMarker("XXX"));
238 converter.write(buf, event);
239 if (buf.length() < 10) {
240 fail("buf is too short");
241 }
242 }
243
244 {
245 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
246 converter.setOptionList(List.of("2", "XXX", "*"));
247 converter.start();
248
249 StringBuilder buf = new StringBuilder();
250 LoggingEvent event = makeLoggingEvent(null);
251 event.addMarker(MarkerFactory.getMarker("YYY"));
252 converter.write(buf, event);
253 if (buf.length() < 10) {
254 fail("buf is too short");
255 }
256 }
257 {
258 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
259 converter.setOptionList(List.of("2", "XXX", "*"));
260 converter.start();
261
262 StringBuilder buf = new StringBuilder();
263 LoggingEvent event = makeLoggingEvent(null);
264 event.addMarker(MarkerFactory.getMarker("YYY"));
265 converter.write(buf, event);
266 if (buf.length() < 10) {
267 fail("buf is too short");
268 }
269 }
270
271 {
272 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
273 converter.setOptionList(List.of("2", "XXX", "*"));
274 converter.start();
275
276 StringBuilder buf = new StringBuilder();
277 converter.write(buf, le);
278 if (buf.length() < 10) {
279 fail("buf is too short");
280 }
281
282 }
283
284 {
285 DynamicConverter<ILoggingEvent> converter = new CallerDataConverter();
286
287 boolean jdk18 = EnvUtil.isJDK18OrHigher();
288
289 converter.setOptionList(jdk18 ? List.of("2..3") : List.of("4..5"));
290 converter.start();
291
292 StringBuilder buf = new StringBuilder();
293 converter.write(buf, le);
294 assertTrue( buf.length() >= 10, "buf is too short");
295
296 String expectedRegex = "Caller\\+4";
297 if(jdk18) {
298 expectedRegex = "Caller\\+2";
299 }
300 expectedRegex+="\t at (java.base\\/)?java.lang.reflect.Method.invoke.*$";
301 String actual = buf.toString();
302 assertTrue( Pattern.compile(expectedRegex).matcher(actual).find(), "actual: " + actual);
303
304 }
305 }
306
307 @Test
308 public void testRelativeTime() throws Exception {
309 DynamicConverter<ILoggingEvent> converter = new RelativeTimeConverter();
310 StringBuilder buf0 = new StringBuilder();
311 StringBuilder buf1 = new StringBuilder();
312 long timestamp = System.currentTimeMillis();
313 LoggingEvent e0 = makeLoggingEvent(null);
314 e0.setTimeStamp(timestamp);
315 LoggingEvent e1 = makeLoggingEvent(null);
316 e1.setTimeStamp(timestamp);
317 converter.write(buf0, e0);
318 converter.write(buf1, e1);
319 assertEquals(buf0.toString(), buf1.toString());
320 }
321
322 @Test
323 public void testSyslogStart() throws Exception {
324 DynamicConverter<ILoggingEvent> converter = new SyslogStartConverter();
325 converter.setOptionList(List.of("MAIL"));
326 converter.start();
327
328 ILoggingEvent event = makeLoggingEvent(null);
329
330 StringBuilder buf = new StringBuilder();
331 converter.write(buf, event);
332
333 String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.INFO_SEVERITY) + ">";
334 assertTrue(buf.toString().startsWith(expected));
335 }
336
337 @Test
338 public void testMDCConverter() throws Exception {
339 logbackMDCAdapter.clear();
340 logbackMDCAdapter.put("someKey", "someValue");
341 MDCConverter converter = new MDCConverter();
342 converter.setOptionList(List.of("someKey"));
343 converter.start();
344
345 ILoggingEvent event = makeLoggingEvent(null);
346
347 String result = converter.convert(event);
348 assertEquals("someValue", result);
349 }
350
351 @Test
352 public void contextNameConverter() {
353 ClassicConverter converter = new ContextNameConverter();
354
355 LoggerContext lcOther = new LoggerContext();
356 lcOther.setName("another");
357 converter.setContext(lcOther);
358
359 loggerContext.setName("aValue");
360 ILoggingEvent event = makeLoggingEvent(null);
361
362 String result = converter.convert(event);
363 assertEquals("aValue", result);
364 }
365
366 @Test
367 public void contextProperty() {
368 PropertyConverter converter = new PropertyConverter();
369 converter.setContext(loggerContext);
370 converter.setOptionList(List.of("k"));
371 converter.start();
372 loggerContext.setName("aValue");
373 loggerContext.putProperty("k", "v");
374 ILoggingEvent event = makeLoggingEvent(null);
375
376 String result = converter.convert(event);
377 assertEquals("v", result);
378 }
379
380 @Test
381 public void testSequenceNumber() {
382
383 SequenceNumberConverter converter = new SequenceNumberConverter();
384 converter.setContext(loggerContext);
385 converter.start();
386
387 assertTrue(converter.isStarted());
388 LoggingEvent event = makeLoggingEvent(null);
389
390 event.setSequenceNumber(123);
391 assertEquals("123", converter.convert(event));
392 StatusPrinter.print(loggerContext);
393 }
394
395 @Test
396 void dateConverterTest() {
397
398 long millis = 1_723_649_365_956L;
399 dateConverterChecker(millis, List.of("STRICT", "GMT"), "2024-08-14T15:29:25,956");
400 dateConverterChecker(millis, List.of("ISO8601", "GMT"), "2024-08-14 15:29:25,956");
401 dateConverterChecker(millis, List.of("ISO8601", "UTC"), "2024-08-14 15:29:25,956");
402 dateConverterChecker(millis, List.of("yyyy-MM-EE", "UTC", "fr-CH"), "2024-08-mer.");
403
404 }
405
406 void dateConverterChecker(long millis, List<String> options, String expected) {
407 DateConverter dateConverter = new DateConverter();
408 dateConverter.setOptionList(options) ;
409 dateConverter.setContext(loggerContext);
410 dateConverter.start();
411
412 assertTrue(dateConverter.isStarted());
413 LoggingEvent event = makeLoggingEvent(null);
414
415 Instant now = Instant.ofEpochMilli(millis);
416 event.setInstant(now);
417 String result = dateConverter.convert(event);
418 assertEquals(expected, result);
419 }
420 }