1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic;
15
16 import ch.qos.logback.classic.joran.JoranConfigurator;
17 import ch.qos.logback.classic.pattern.ConverterTest;
18 import ch.qos.logback.classic.pattern.ExceptionalConverter2;
19 import ch.qos.logback.classic.spi.ILoggingEvent;
20 import ch.qos.logback.classic.spi.LoggingEvent;
21 import ch.qos.logback.classic.pattern.SampleConverter;
22 import ch.qos.logback.classic.util.LogbackMDCAdapter;
23 import ch.qos.logback.core.Context;
24 import ch.qos.logback.core.joran.spi.JoranException;
25 import ch.qos.logback.core.pattern.PatternLayoutBase;
26 import ch.qos.logback.core.pattern.parser.test.AbstractPatternLayoutBaseTest;
27 import ch.qos.logback.core.spi.ScanException;
28 import ch.qos.logback.core.testUtil.RandomUtil;
29 import ch.qos.logback.core.testUtil.StringListAppender;
30 import ch.qos.logback.core.util.OptionHelper;
31 import ch.qos.logback.core.util.StatusPrinter;
32 import org.junit.jupiter.api.BeforeEach;
33 import org.junit.jupiter.api.Test;
34 import org.slf4j.MDC;
35
36 import static ch.qos.logback.classic.ClassicTestConstants.ISO_REGEX;
37 import static ch.qos.logback.classic.ClassicTestConstants.MAIN_REGEX;
38 import static org.junit.jupiter.api.Assertions.assertEquals;
39 import static org.junit.jupiter.api.Assertions.assertNotNull;
40 import static org.junit.jupiter.api.Assertions.assertTrue;
41
42 import java.time.Instant;
43
44 public class PatternLayoutTest extends AbstractPatternLayoutBaseTest<ILoggingEvent> {
45
46 private PatternLayout pl = new PatternLayout();
47 private LoggerContext loggerContext = new LoggerContext();
48
49 LogbackMDCAdapter logbackMDCAdapter = new LogbackMDCAdapter();
50 Logger logger = loggerContext.getLogger(ConverterTest.class);
51 Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
52
53 int diff = RandomUtil.getPositiveInt();
54
55 String aMessage = "Some message";
56
57 Exception ex = new Exception("Bogus exception");
58
59
60
61 @BeforeEach
62 public void setUp() {
63 loggerContext.setMDCAdapter(logbackMDCAdapter);
64 pl.setContext(loggerContext);
65
66 }
67
68
69
70
71
72
73 protected String getExceptionalConverterClassName() {
74 return ExceptionalConverter2.class.getName();
75 }
76
77 LoggingEvent makeLoggingEvent(String msg, Exception ex) {
78 return new LoggingEvent(ch.qos.logback.core.pattern.FormattingConverter.class.getName(), logger, Level.INFO,
79 msg, ex, null);
80 }
81
82 public ILoggingEvent getEventObject() {
83 return makeLoggingEvent("Some message", null);
84 }
85
86 public PatternLayoutBase<ILoggingEvent> getPatternLayoutBase() {
87 return new PatternLayout();
88 }
89
90 @Test
91 public void testOK() {
92 pl.setPattern("%d %le [%t] %lo{30} - %m%n");
93 pl.start();
94 String val = pl.doLayout(getEventObject());
95
96
97
98
99 String regex = ISO_REGEX + " INFO " + MAIN_REGEX + " c.q.l.c.pattern.ConverterTest - Some message\\s*";
100
101 assertTrue( val.matches(regex), "val=" + val);
102 }
103
104 @Test
105 public void testNoExeptionHandler() {
106 pl.setPattern("%m%n");
107 pl.start();
108 String val = pl.doLayout(makeLoggingEvent(aMessage, ex));
109 assertTrue(val.contains("java.lang.Exception: Bogus exception"));
110 }
111
112 @Test
113 public void testCompositePattern() {
114 pl.setPattern("%-56(%d %lo{20}) - %m%n");
115 pl.start();
116 String val = pl.doLayout(getEventObject());
117
118 String regex = ISO_REGEX + " c.q.l.c.p.ConverterTest - Some message\\s*";
119 assertTrue(val.matches(regex));
120 }
121
122 @Test
123 public void contextProperty() {
124 pl.setPattern("%property{a}");
125 pl.start();
126 loggerContext.putProperty("a", "b");
127
128 String val = pl.doLayout(getEventObject());
129 assertEquals("b", val);
130 }
131
132 @Test
133 public void testNopExeptionHandler() {
134 pl.setPattern("%nopex %m%n");
135 pl.start();
136 String val = pl.doLayout(makeLoggingEvent(aMessage, ex));
137 assertTrue(!val.contains("java.lang.Exception: Bogus exception"));
138 }
139
140 @Test
141 public void testWithParenthesis() {
142 pl.setPattern("\\(%msg:%msg\\) %msg");
143 pl.start();
144 LoggingEvent le = makeLoggingEvent(aMessage, null);
145 String val = pl.doLayout(le);
146 assertEquals("(Some message:Some message) Some message", val);
147 }
148
149 @Test
150 public void testWithLettersComingFromLog4j() {
151
152 pl.setPattern("%d %p [%t] %c{30} - %m%n");
153 pl.start();
154 String val = pl.doLayout(getEventObject());
155
156
157 String regex = ClassicTestConstants.ISO_REGEX + " INFO " + MAIN_REGEX
158 + " c.q.l.c.pattern.ConverterTest - Some message\\s*";
159 assertTrue(val.matches(regex));
160 }
161
162 @Test
163 public void mdcWithDefaultValue() throws ScanException {
164 String pattern = "%msg %mdc{foo1} %mdc{bar:-[null]}";
165 pl.setPattern(OptionHelper.substVars(pattern, loggerContext));
166 pl.start();
167
168 String key = "foo1";
169
170 logbackMDCAdapter.put(key, key);
171 try {
172 String val = pl.doLayout(getEventObject());
173 assertEquals("Some message foo1 [null]", val);
174 } finally {
175 logbackMDCAdapter.remove(key);
176 }
177 }
178
179 @Test
180 public void contextNameTest() {
181 pl.setPattern("%contextName");
182 loggerContext.setName("aValue");
183 pl.start();
184 String val = pl.doLayout(getEventObject());
185 assertEquals("aValue", val);
186 }
187
188 @Test
189 public void cnTest() {
190 pl.setPattern("%cn");
191 loggerContext.setName("aValue");
192 pl.start();
193 String val = pl.doLayout(getEventObject());
194 assertEquals("aValue", val);
195 }
196
197 @Test
198 public void micros() {
199 verifyMicros(122_891_479, "2011-12-03 10:15:30.122 891 Some message");
200 verifyMicros(122_091_479, "2011-12-03 10:15:30.122 091 Some message");
201 verifyMicros(122_001_479, "2011-12-03 10:15:30.122 001 Some message");
202 }
203
204 void verifyMicros(int nanos, String expected) {
205 Instant instant = Instant.parse("2011-12-03T10:15:30Z");
206 instant = instant.plusNanos(nanos);
207 LoggingEvent le = makeLoggingEvent(aMessage, null);
208 le.setInstant(instant);
209
210 pl.setPattern("%date{yyyy-MM-dd HH:mm:ss.SSS, UTC} %micros %message%nopex");
211 pl.start();
212
213 String val = pl.doLayout(le);
214 assertEquals(expected, val);
215 }
216
217 @Override
218 public Context getContext() {
219 return loggerContext;
220 }
221
222 void configure(String file) throws JoranException {
223 JoranConfigurator jc = new JoranConfigurator();
224 jc.setContext(loggerContext);
225 jc.doConfigure(file);
226 }
227
228 @Test
229 public void testConversionRuleSupportInPatternLayout() throws JoranException {
230 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/patternLayout0.xml");
231 root.getAppender("LIST");
232 String msg = "Simon says";
233 logger.debug(msg);
234 StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
235 assertNotNull(sla);
236 assertEquals(1, sla.strList.size());
237 assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
238 }
239
240 @Test
241 public void testConversionRuleAtEnd() throws JoranException {
242 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/conversionRuleAtEnd.xml");
243 root.getAppender("LIST");
244 String msg = "testConversionRuleAtEnd";
245 logger.debug(msg);
246 StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
247 assertNotNull(sla);
248 assertEquals(1, sla.strList.size());
249 assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
250 }
251
252 @Test
253 public void testConversionRuleInIncluded() throws JoranException {
254 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/conversionRuleTop0.xml");
255 StatusPrinter.print(loggerContext);
256 root.getAppender("LIST");
257 String msg = "testConversionRuleInIncluded";
258 logger.debug(msg);
259 StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
260 assertNotNull(sla);
261 assertEquals(1, sla.strList.size());
262 assertEquals(SampleConverter.SAMPLE_STR + " - " + msg, sla.strList.get(0));
263 }
264
265 @Test
266 public void smokeReplace() {
267 pl.setPattern("%replace(a1234b){'\\d{4}', 'XXXX'}");
268 pl.start();
269 String val = pl.doLayout(getEventObject());
270 assertEquals("aXXXXb", val);
271 }
272
273 @Test
274 public void replaceNewline() throws ScanException {
275 String pattern = "%replace(A\nB){'\n', '\n\t'}";
276 String substPattern = OptionHelper.substVars(pattern, null, loggerContext);
277 assertEquals(pattern, substPattern);
278 pl.setPattern(substPattern);
279 pl.start();
280
281 String val = pl.doLayout(makeLoggingEvent("", null));
282 assertEquals("A\n\tB", val);
283 }
284
285 @Test
286 public void replaceWithJoran() throws JoranException {
287 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "pattern/replace0.xml");
288
289 root.getAppender("LIST");
290 String msg = "And the number is 4111111111110000, expiring on 12/2010";
291 logger.debug(msg);
292 StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
293 assertNotNull(sla);
294 assertEquals(1, sla.strList.size());
295 assertEquals("And the number is XXXX, expiring on 12/2010", sla.strList.get(0));
296 }
297
298 @Test
299 public void replaceWithJoran_NEWLINE() throws JoranException {
300 loggerContext.putProperty("TAB", "\t");
301 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "pattern/replaceNewline.xml");
302
303 root.getAppender("LIST");
304 String msg = "A\nC";
305 logger.debug(msg);
306 StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
307 assertNotNull(sla);
308 assertEquals(1, sla.strList.size());
309 assertEquals("A\n\tC", sla.strList.get(0));
310 }
311
312 @Test
313 public void prefixConverterSmoke() {
314 String pattern = "%prefix(%logger) %message";
315 pl.setPattern(pattern);
316 pl.start();
317 String val = pl.doLayout(makeLoggingEvent("hello", null));
318 assertEquals("logger=" + logger.getName() + " hello", val);
319 }
320
321 @Test
322 public void prefixConverterWithMDC() {
323 String mdcKey = "boo";
324 String mdcVal = "moo";
325
326 String pattern = "%prefix(%level %logger %X{" + mdcKey + "}) %message";
327 pl.setPattern(pattern);
328 pl.start();
329 logbackMDCAdapter.put(mdcKey, mdcVal);
330 try {
331 String val = pl.doLayout(makeLoggingEvent("hello", null));
332
333 assertEquals("level=" + "INFO logger=" + logger.getName() + " " + mdcKey + "=" + mdcVal + " hello", val);
334
335 } finally {
336 MDC.remove(mdcKey);
337 }
338 }
339
340 @Test
341 public void prefixConverterWithProperty() {
342
343 try {
344 String propertyKey = "px1953";
345 String propertyVal = "pxVal";
346
347 System.setProperty(propertyKey, propertyVal);
348
349 String pattern = "%prefix(%logger %property{" + propertyKey + "}) %message";
350 pl.setPattern(pattern);
351 pl.start();
352
353 String val = pl.doLayout(makeLoggingEvent("hello", null));
354
355 assertEquals("logger=" + logger.getName() + " " + propertyKey + "=" + propertyVal + " hello", val);
356
357 } finally {
358 System.clearProperty("px");
359 }
360 }
361
362 }