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