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