View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j;
19  
20  import junit.framework.TestCase;
21  import org.apache.log4j.util.AbsoluteDateAndTimeFilter;
22  import org.apache.log4j.util.AbsoluteTimeFilter;
23  import org.apache.log4j.util.Compare;
24  import org.apache.log4j.util.ControlFilter;
25  import org.apache.log4j.util.Filter;
26  import org.apache.log4j.util.ISO8601Filter;
27  import org.apache.log4j.util.JunitTestRunnerFilter;
28  import org.apache.log4j.util.LineNumberFilter;
29  import org.apache.log4j.util.RelativeTimeFilter;
30  import org.apache.log4j.util.SunReflectFilter;
31  import org.apache.log4j.util.Transformer;
32  import org.apache.log4j.util.MDCOrderFilter;
33  import org.apache.log4j.spi.ThrowableInformation;
34  
35  import java.text.ParsePosition;
36  import java.text.SimpleDateFormat;
37  import java.util.Date;
38  import java.util.TimeZone;
39  import java.io.*;
40  import java.util.Properties;
41  
42  
43  public class EnhancedPatternLayoutTestCase extends TestCase {
44    static String TEMP = "temp";
45    static String FILTERED = "filtered";
46    static String EXCEPTION1 = "java.lang.Exception: Just testing";
47    static String EXCEPTION2 = "//s*at .*//(.*://d{1,4}//)";
48    static String EXCEPTION3 = "//s*at .*//((Native Method|Unknown Source)//)";
49    static String EXCEPTION4 = "//s*at .*//(.*Compiled Code//)";
50  
51    static String PAT0 =
52      "//[main]// (DEBUG|INFO|WARN|ERROR|FATAL) .* - Message //d{1,2}";
53    static String PAT1 = Filter.ISO8601_PAT + " " + PAT0;
54    static String PAT2 = Filter.ABSOLUTE_DATE_AND_TIME_PAT + " " + PAT0;
55    static String PAT3 = Filter.ABSOLUTE_TIME_PAT + " " + PAT0;
56    static String PAT4 = Filter.RELATIVE_TIME_PAT + " " + PAT0;
57    static String PAT5 =
58      "//[main]// (DEBUG|INFO|WARN|ERROR|FATAL) .* : Message //d{1,2}";
59    static String PAT6 =
60      "//[main]// (DEBUG|INFO |WARN |ERROR|FATAL) org.apache.log4j.EnhancedPatternLayoutTestCase.common//(EnhancedPatternLayoutTestCase.java://d{1,4}//): Message //d{1,2}";
61    static String PAT11a =
62      "^(DEBUG|INFO |WARN |ERROR|FATAL) //[main]// log4j.EnhancedPatternLayoutTest: Message //d{1,2}";
63    static String PAT11b =
64      "^(DEBUG|INFO |WARN |ERROR|FATAL) //[main]// root: Message //d{1,2}";
65    static String PAT12 =
66      "^//[main]// (DEBUG|INFO |WARN |ERROR|FATAL) "
67      + "org.apache.log4j.EnhancedPatternLayoutTestCase.common//(EnhancedPatternLayoutTestCase.java://d{3}//): "
68      + "Message //d{1,2}";
69    static String PAT13 =
70      "^//[main]// (DEBUG|INFO |WARN |ERROR|FATAL) "
71      + "apache.log4j.EnhancedPatternLayoutTestCase.common//(EnhancedPatternLayoutTestCase.java://d{3}//): "
72      + "Message //d{1,2}";
73    static String PAT14 =
74      "^(TRACE|DEBUG| INFO| WARN|ERROR|FATAL)// //d{1,2}// *- Message //d{1,2}";
75    static String PAT_MDC_1 = "";
76    Logger root;
77    Logger logger;
78  
79    public EnhancedPatternLayoutTestCase(final String name) {
80      super(name);
81    }
82  
83    public void setUp() {
84      root = Logger.getRootLogger();
85      logger = Logger.getLogger(EnhancedPatternLayoutTest.class);
86    }
87  
88    public void tearDown() {
89      root.getLoggerRepository().resetConfiguration();
90    }
91  
92      /***
93       * Configures log4j from a properties file resource in class loader path.
94       * @param fileName resource name, only last element is significant.
95       * @throws IOException if resource not found or error reading resource.
96       */
97    private static void configure(final String fileName) throws IOException {
98          String resourceName = fileName;
99          int lastSlash = resourceName.lastIndexOf("/");
100         if (lastSlash >= 0) {
101              resourceName = resourceName.substring(lastSlash + 1);
102         }
103         InputStream is = EnhancedPatternLayoutTestCase.class.getResourceAsStream(resourceName);
104         if (is == null) {
105             throw new FileNotFoundException("Could not find resource " + resourceName);
106         }
107         Properties props = new Properties();
108         props.load(is);
109         PropertyConfigurator.configure(props);
110   }
111 
112     /***
113      * Compares actual and expected files.
114      * @param actual file name for file generated by test
115      * @param expected resource name containing expected output
116      * @return true if files are the same after adjustments
117      * @throws IOException if IO error during comparison.
118      */
119   private static boolean compare(final String actual,
120                                  final String expected) throws IOException {
121       return Compare.compare(EnhancedPatternLayoutTestCase.class, actual, expected);
122   }
123 
124 
125   public void test1() throws Exception {
126     configure("input/pattern/enhancedPatternLayout1.properties");
127     common();
128     Transformer.transform(
129       TEMP, FILTERED,
130       new Filter[] {
131         new LineNumberFilter(), new SunReflectFilter(),
132         new JunitTestRunnerFilter()
133       });
134     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.1"));
135   }
136 
137   public void test2() throws Exception {
138     configure("input/pattern/enhancedPatternLayout2.properties");
139     common();
140 
141     ControlFilter cf1 =
142       new ControlFilter(
143         new String[] { PAT1, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
144     Transformer.transform(
145       TEMP, FILTERED,
146       new Filter[] {
147         cf1, new LineNumberFilter(), new ISO8601Filter(),
148         new SunReflectFilter(), new JunitTestRunnerFilter()
149       });
150     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.2"));
151   }
152 
153   public void test3() throws Exception {
154     configure("input/pattern/enhancedPatternLayout3.properties");
155     common();
156 
157     ControlFilter cf1 =
158       new ControlFilter(
159         new String[] { PAT1, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
160     Transformer.transform(
161       TEMP, FILTERED,
162       new Filter[] {
163         cf1, new LineNumberFilter(), new ISO8601Filter(),
164         new SunReflectFilter(), new JunitTestRunnerFilter()
165       });
166     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.3"));
167   }
168 
169   // Output format:
170   // 06 avr. 2002 18:30:58,937 [main] DEBUG atternLayoutTest - Message 0  
171   public void test4() throws Exception {
172     configure("input/pattern/enhancedPatternLayout4.properties");
173     common();
174 
175     ControlFilter cf1 =
176       new ControlFilter(
177         new String[] { PAT2, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
178     Transformer.transform(
179       TEMP, FILTERED,
180       new Filter[] {
181         cf1, new LineNumberFilter(), new AbsoluteDateAndTimeFilter(),
182         new SunReflectFilter(), new JunitTestRunnerFilter()
183       });
184     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.4"));
185   }
186 
187   public void test5() throws Exception {
188     configure("input/pattern/enhancedPatternLayout5.properties");
189     common();
190 
191     ControlFilter cf1 =
192       new ControlFilter(
193         new String[] { PAT2, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
194     Transformer.transform(
195       TEMP, FILTERED,
196       new Filter[] {
197         cf1, new LineNumberFilter(), new AbsoluteDateAndTimeFilter(),
198         new SunReflectFilter(), new JunitTestRunnerFilter()
199       });
200     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.5"));
201   }
202 
203   // 18:54:19,201 [main] DEBUG atternLayoutTest - Message 0
204   public void test6() throws Exception {
205     configure("input/pattern/enhancedPatternLayout6.properties");
206     common();
207 
208     ControlFilter cf1 =
209       new ControlFilter(
210         new String[] { PAT3, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
211     Transformer.transform(
212       TEMP, FILTERED,
213       new Filter[] {
214         cf1, new LineNumberFilter(), new AbsoluteTimeFilter(),
215         new SunReflectFilter(), new JunitTestRunnerFilter()
216       });
217     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.6"));
218   }
219 
220   public void test7() throws Exception {
221     configure("input/pattern/enhancedPatternLayout7.properties");
222     common();
223 
224     ControlFilter cf1 =
225       new ControlFilter(
226         new String[] { PAT3, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
227     Transformer.transform(
228       TEMP, FILTERED,
229       new Filter[] {
230         cf1, new LineNumberFilter(), new AbsoluteTimeFilter(),
231         new SunReflectFilter(), new JunitTestRunnerFilter()
232       });
233     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.7"));
234   }
235 
236   public void test8() throws Exception {
237     configure("input/pattern/enhancedPatternLayout8.properties");
238     common();
239 
240     ControlFilter cf1 =
241       new ControlFilter(
242         new String[] { PAT4, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
243     Transformer.transform(
244       TEMP, FILTERED,
245       new Filter[] {
246         cf1, new LineNumberFilter(), new RelativeTimeFilter(),
247         new SunReflectFilter(), new JunitTestRunnerFilter()
248       });
249     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.8"));
250   }
251 
252   public void test9() throws Exception {
253     configure("input/pattern/enhancedPatternLayout9.properties");
254     common();
255 
256     ControlFilter cf1 =
257       new ControlFilter(
258         new String[] { PAT5, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
259     Transformer.transform(
260       TEMP, FILTERED,
261       new Filter[] {
262         cf1, new LineNumberFilter(), new SunReflectFilter(),
263         new JunitTestRunnerFilter()
264       });
265     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.9"));
266   }
267 
268   public void test10() throws Exception {
269     configure("input/pattern/enhancedPatternLayout10.properties");
270     common();
271 
272     ControlFilter cf1 =
273       new ControlFilter(
274         new String[] { PAT6, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
275     Transformer.transform(
276       TEMP, FILTERED,
277       new Filter[] {
278         cf1, new LineNumberFilter(), new SunReflectFilter(),
279         new JunitTestRunnerFilter()
280       });
281     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.10"));
282   }
283 
284   public void test11() throws Exception {
285     configure("input/pattern/enhancedPatternLayout11.properties");
286     common();
287 
288     ControlFilter cf1 =
289       new ControlFilter(
290         new String[] { PAT11a, PAT11b, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
291     Transformer.transform(
292       TEMP, FILTERED,
293       new Filter[] {
294         cf1, new LineNumberFilter(), new SunReflectFilter(),
295         new JunitTestRunnerFilter()
296       });
297     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.11"));
298   }
299 
300   public void test12() throws Exception {
301     configure("input/pattern/enhancedPatternLayout12.properties");
302     common();
303 
304     ControlFilter cf1 =
305       new ControlFilter(
306         new String[] { PAT12, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
307     Transformer.transform(
308       TEMP, FILTERED,
309       new Filter[] {
310         cf1, new LineNumberFilter(), new SunReflectFilter(),
311         new JunitTestRunnerFilter()
312       });
313     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.12"));
314   }
315 
316   public void test13() throws Exception {
317     configure("input/pattern/enhancedPatternLayout13.properties");
318     common();
319 
320     ControlFilter cf1 =
321       new ControlFilter(
322         new String[] { PAT13, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
323     Transformer.transform(
324       TEMP, FILTERED,
325       new Filter[] {
326         cf1, new LineNumberFilter(), new SunReflectFilter(),
327         new JunitTestRunnerFilter()
328       });
329     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.13"));
330   }
331 
332     /***
333      * Test of class abbreviation.
334      *
335      * @throws Exception
336      */
337     public void test14() throws Exception {
338       configure("input/pattern/enhancedPatternLayout14.properties");
339       common();
340 
341       Transformer.transform(
342         TEMP, FILTERED,
343         new Filter[] {
344           new LineNumberFilter(), new SunReflectFilter(),
345           new JunitTestRunnerFilter()
346         });
347       assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.14"));
348     }
349 
350 
351     private static void clearMDC() throws Exception {
352         java.util.Hashtable context = MDC.getContext();
353         if (context != null) {
354             context.clear();
355         }
356     }
357 
358   public void testMDC1() throws Exception {
359     configure("input/pattern/enhancedPatternLayout.mdc.1.properties");
360     clearMDC();
361     MDC.put("key1", "va11");
362     MDC.put("key2", "va12");
363     logger.debug("Hello World");
364     MDC.remove("key1");
365     MDC.remove("key2");
366 
367     Transformer.transform(
368       TEMP, FILTERED,
369       new Filter[] {
370         new LineNumberFilter(), new SunReflectFilter(),
371         new JunitTestRunnerFilter(),
372         new MDCOrderFilter()
373       });
374     assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.mdc.1"));
375   }
376     /***
377      * Tests log4j 1.2 style extension of EnhancedPatternLayout.
378      * Was test14 in log4j 1.2.
379      * @throws Exception
380      */
381     public void test15() throws Exception {
382       configure("input/pattern/enhancedPatternLayout15.properties");
383       common();
384       ControlFilter cf1 = new ControlFilter(new String[]{PAT14, EXCEPTION1,
385                                  EXCEPTION2, EXCEPTION3, EXCEPTION4});
386       Transformer.transform(
387         TEMP, FILTERED,
388         new Filter[] {
389           cf1, new LineNumberFilter(), new SunReflectFilter(),
390           new JunitTestRunnerFilter()
391         });
392       assertTrue(compare(FILTERED, "witness/pattern/enhancedPatternLayout.15"));
393     }
394     /***
395      * Tests explicit UTC time zone in pattern.
396      * @throws Exception
397      */
398     public void test16() throws Exception {
399       final long start = new Date().getTime();
400       configure("input/pattern/enhancedPatternLayout16.properties");
401       common();
402       final long end = new Date().getTime();
403       FileReader reader = new FileReader("patternLayout16.log");
404       char chars[] = new char[50];
405       reader.read(chars, 0, chars.length);
406       reader.close();
407       SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
408       format.setTimeZone(TimeZone.getTimeZone("GMT+0"));
409       String utcStr = new String(chars, 0, 19);
410       Date utcDate = format.parse(utcStr, new ParsePosition(0));
411       assertTrue(utcDate.getTime() >= start - 1000 && utcDate.getTime() < end + 1000);
412       String cstStr = new String(chars, 21, 19);
413       format.setTimeZone(TimeZone.getTimeZone("GMT-6"));
414       Date cstDate = format.parse(cstStr, new ParsePosition(0));
415       assertFalse(cstStr.equals(utcStr));
416       assertTrue(cstDate.getTime() >= start - 1000 && cstDate.getTime() < end + 1000);
417     }
418 
419   /***
420    *   Test left and right truncation
421    */
422   public void test17() throws Exception {
423     configure("input/pattern/enhancedPatternLayout17.properties");
424     root.info("012");
425     root.info("");
426     root.info("12345");
427     root.info("0123456789");
428     assertTrue(compare("patternLayout17.log", "witness/pattern/enhancedPatternLayout.17"));
429   }
430 
431 
432   void common() {
433     int i = -1;
434 
435     logger.debug("Message " + ++i);
436     root.debug("Message " + i);
437 
438     logger.info("Message " + ++i);
439     root.info("Message " + i);
440 
441     logger.warn("Message " + ++i);
442     root.warn("Message " + i);
443 
444     logger.error("Message " + ++i);
445     root.error("Message " + i);
446 
447     logger.log(Level.FATAL, "Message " + ++i);
448     root.log(Level.FATAL, "Message " + i);
449 
450     Exception e = new Exception("Just testing");
451 
452     logger.debug("Message " + ++i, e);
453     logger.info("Message " + ++i, e);
454     logger.warn("Message " + ++i, e);
455     logger.error("Message " + ++i, e);
456     logger.log(Level.FATAL, "Message " + ++i, e);
457   }
458 
459   /***
460     Test case for MDC conversion pattern. */
461   public void testMDC2() throws Exception {
462     String OUTPUT_FILE   = "patternLayout.mdc.2";
463     String WITNESS_FILE  = "witness/pattern/enhancedPatternLayout.mdc.2";
464     
465     String mdcMsgPattern1 = "%m : %X%n";
466     String mdcMsgPattern2 = "%m : %X{key1}%n";
467     String mdcMsgPattern3 = "%m : %X{key2}%n";
468     String mdcMsgPattern4 = "%m : %X{key3}%n";
469     String mdcMsgPattern5 = "%m : %X{key1},%X{key2},%X{key3}%n";
470     
471     // set up appender
472     EnhancedPatternLayout layout = new EnhancedPatternLayout("%m%n");
473     Appender appender = new FileAppender(layout, OUTPUT_FILE, false);
474             
475     // set appender on root and set level to debug
476     root.addAppender(appender);
477     root.setLevel(Level.DEBUG);
478 
479     clearMDC();
480     // output starting message
481     root.debug("starting mdc pattern test");
482  
483     layout.setConversionPattern(mdcMsgPattern1);
484     layout.activateOptions();
485     root.debug("empty mdc, no key specified in pattern");
486     
487     layout.setConversionPattern(mdcMsgPattern2);
488     layout.activateOptions();
489     root.debug("empty mdc, key1 in pattern");
490     
491     layout.setConversionPattern(mdcMsgPattern3);
492     layout.activateOptions();
493     root.debug("empty mdc, key2 in pattern");
494     
495     layout.setConversionPattern(mdcMsgPattern4);
496     layout.activateOptions();
497     root.debug("empty mdc, key3 in pattern");
498     
499     layout.setConversionPattern(mdcMsgPattern5);
500     layout.activateOptions();
501     root.debug("empty mdc, key1, key2, and key3 in pattern");
502 
503     MDC.put("key1", "value1");
504     MDC.put("key2", "value2");
505 
506     layout.setConversionPattern(mdcMsgPattern1);
507     layout.activateOptions();
508     root.debug("filled mdc, no key specified in pattern");
509     
510     layout.setConversionPattern(mdcMsgPattern2);
511     layout.activateOptions();
512     root.debug("filled mdc, key1 in pattern");
513     
514     layout.setConversionPattern(mdcMsgPattern3);
515     layout.activateOptions();
516     root.debug("filled mdc, key2 in pattern");
517     
518     layout.setConversionPattern(mdcMsgPattern4);
519     layout.activateOptions();
520     root.debug("filled mdc, key3 in pattern");
521     
522     layout.setConversionPattern(mdcMsgPattern5);
523     layout.activateOptions();
524     root.debug("filled mdc, key1, key2, and key3 in pattern");
525 
526     MDC.remove("key1");
527     MDC.remove("key2");
528 
529     layout.setConversionPattern("%m%n");
530     layout.activateOptions();
531     root.debug("finished mdc pattern test");
532 
533 
534       Transformer.transform(
535         OUTPUT_FILE, FILTERED,
536         new Filter[] {
537           new LineNumberFilter(), new SunReflectFilter(),
538           new JunitTestRunnerFilter(),
539           new MDCOrderFilter()
540         });
541 
542     assertTrue(compare(FILTERED, WITNESS_FILE));
543   }
544   /***
545     Test case for throwable conversion pattern. */
546   public void testThrowable() throws Exception {
547     String OUTPUT_FILE   = "patternLayout.throwable";
548     String WITNESS_FILE  = "witness/pattern/enhancedPatternLayout.throwable";
549     
550     
551     // set up appender
552     EnhancedPatternLayout layout = new EnhancedPatternLayout("%m%n");
553     Appender appender = new FileAppender(layout, OUTPUT_FILE, false);
554             
555     // set appender on root and set level to debug
556     root.addAppender(appender);
557     root.setLevel(Level.DEBUG);
558     
559     // output starting message
560     root.debug("starting throwable pattern test");
561      Exception ex = new Exception("Test Exception");
562     root.debug("plain pattern, no exception");
563     root.debug("plain pattern, with exception", ex);
564     layout.setConversionPattern("%m%n%throwable");
565     layout.activateOptions();
566     root.debug("%throwable, no exception");
567     root.debug("%throwable, with exception", ex);
568 
569     layout.setConversionPattern("%m%n%throwable{short}");
570     layout.activateOptions();
571     root.debug("%throwable{short}, no exception");
572     root.debug("%throwable{short}, with exception", ex);
573 
574     layout.setConversionPattern("%m%n%throwable{none}");
575     layout.activateOptions();
576     root.debug("%throwable{none}, no exception");
577     root.debug("%throwable{none}, with exception", ex);
578 
579 
580     layout.setConversionPattern("%m%n%throwable{0}");
581     layout.activateOptions();
582     root.debug("%throwable{0}, no exception");
583     root.debug("%throwable{0}, with exception", ex);
584 
585     layout.setConversionPattern("%m%n%throwable{1}");
586     layout.activateOptions();
587     root.debug("%throwable{1}, no exception");
588     root.debug("%throwable{1}, with exception", ex);
589 
590     layout.setConversionPattern("%m%n%throwable{100}");
591     layout.activateOptions();
592     root.debug("%throwable{100}, no exception");
593     root.debug("%throwable{100}, with exception", ex);
594 
595     //
596     //  manufacture a pattern to get just the first two lines
597     //
598     String[] trace = new ThrowableInformation(ex).getThrowableStrRep();
599     layout.setConversionPattern("%m%n%throwable{" + (2 - trace.length) + "}");
600     layout.activateOptions();
601     root.debug("%throwable{-n}, no exception");
602     root.debug("%throwable{-n}, with exception", ex);
603 
604 
605       Transformer.transform(
606         OUTPUT_FILE, FILTERED,
607         new Filter[] {
608           new LineNumberFilter(), new SunReflectFilter(),
609           new JunitTestRunnerFilter(),
610           new MDCOrderFilter()
611         });
612 
613     assertTrue(compare(FILTERED, WITNESS_FILE));
614   }
615 }