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.net;
19  
20  import junit.framework.TestCase;
21  
22  import org.apache.log4j.AsyncAppender;
23  import org.apache.log4j.Layout;
24  import org.apache.log4j.Level;
25  import org.apache.log4j.LogManager;
26  import org.apache.log4j.Logger;
27  import org.apache.log4j.PatternLayout;
28  import org.apache.log4j.VectorErrorHandler;
29  import org.apache.log4j.HTMLLayout;
30  
31  import java.util.StringTokenizer;
32  import java.net.DatagramSocket;
33  import java.net.DatagramPacket;
34  import java.text.SimpleDateFormat;
35  import java.util.Locale;
36  import java.util.Date;
37  import java.util.Calendar;
38  
39  
40  /***
41   *    Tests for SyslogAppender
42   *
43   *
44   * */
45  public class SyslogAppenderTest extends TestCase {
46    /***
47     * Create new instance of SyslogAppenderTest.
48     * @param testName test name
49     */
50    public SyslogAppenderTest(final String testName) {
51      super(testName);
52    }
53  
54    /***
55      * Resets configuration after every test.
56    */
57    public void tearDown() {
58      LogManager.resetConfiguration();
59    }
60  
61    /***
62     * Test default constructor.
63     */
64    public void testDefaultConstructor() {
65      SyslogAppender appender = new SyslogAppender();
66      assertEquals("user", appender.getFacility());
67      assertEquals(false, appender.getFacilityPrinting());
68      assertNull(appender.getLayout());
69      assertNull(appender.getSyslogHost());
70      assertTrue(appender.requiresLayout());
71    }
72  
73    /***
74     * Test two parameter constructor.
75     */
76    public void testTwoParamConstructor() {
77      Layout layout = new PatternLayout();
78      SyslogAppender appender = new SyslogAppender(layout, 24);
79      assertEquals("daemon", appender.getFacility());
80      assertEquals(false, appender.getFacilityPrinting());
81      assertEquals(layout, appender.getLayout());
82      assertNull(appender.getSyslogHost());
83      assertTrue(appender.requiresLayout());
84    }
85  
86    /***
87     * Test two parameter constructor with unexpected facility.
88     */
89    public void testTwoParamConstructorBadFacility() {
90      Layout layout = new PatternLayout();
91      SyslogAppender appender = new SyslogAppender(layout, 25);
92      assertEquals("user", appender.getFacility());
93      assertEquals(false, appender.getFacilityPrinting());
94      assertEquals(layout, appender.getLayout());
95      assertNull(appender.getSyslogHost());
96      assertTrue(appender.requiresLayout());
97    }
98  
99    /***
100    * Test three parameter constructor.
101    */
102   public void testThreeParamConstructor() {
103     Layout layout = new PatternLayout();
104     SyslogAppender appender =
105       new SyslogAppender(layout, "syslog.example.org", 24);
106     assertEquals("daemon", appender.getFacility());
107     assertEquals(false, appender.getFacilityPrinting());
108     assertEquals(layout, appender.getLayout());
109     assertEquals("syslog.example.org", appender.getSyslogHost());
110     assertTrue(appender.requiresLayout());
111   }
112 
113   /***
114    * Test getFacilityString for expected facility codes.
115    */
116   public void testGetFacilityString() {
117     String expected =
118       "kern user mail daemon auth syslog lpr news "
119       + "uucp cron authpriv ftp local0 local1 local2 local3 "
120       + "local4 local5 local6 local7 ";
121     StringBuffer actual = new StringBuffer();
122 
123     for (int i = 0; i <= 11; i++) {
124       actual.append(SyslogAppender.getFacilityString(i << 3));
125       actual.append(' ');
126     }
127 
128     for (int i = 16; i <= 23; i++) {
129       actual.append(SyslogAppender.getFacilityString(i << 3));
130       actual.append(' ');
131     }
132 
133     assertEquals(expected, actual.toString());
134   }
135 
136   /***
137    * Test getFacilityString for some unexpected facility codes.
138    */
139   public void testGetFacilityStringUnexpected() {
140     assertNull(SyslogAppender.getFacilityString(1));
141     assertNull(SyslogAppender.getFacilityString(12 << 3));
142   }
143 
144   /***
145    * Test getFacility with a bogus facility name.
146    */
147   public void testGetFacilityBogus() {
148     assertEquals(-1, SyslogAppender.getFacility("bogus"));
149   }
150 
151   /***
152    * Test getFacility with a null facility name.
153    */
154   public void testGetFacilityNull() {
155     assertEquals(-1, SyslogAppender.getFacility(null));
156   }
157 
158   /***
159    * Test getFacility for expected system facility names.
160    */
161   public void testGetFacilitySystemNames() {
162     String[] names =
163       new String[] {
164         "kErn", "usEr", "MaIL", "daemOn", "auTh", "syslOg", "lPr", "newS",
165         "Uucp", "croN", "authprIv", "ftP"
166       };
167 
168     for (int i = 0; i <= 11; i++) {
169       assertEquals(i << 3, SyslogAppender.getFacility(names[i]));
170     }
171   }
172 
173   /***
174    * Test getFacility for expected system facility names.
175    */
176   public void testGetFacilityLocalNames() {
177     String[] names =
178       new String[] {
179         "lOcal0", "LOCAL1", "loCal2", "locAl3", "locaL4", "local5", "LOCal6",
180         "loCAL7"
181       };
182 
183     for (int i = 0; i <= 7; i++) {
184       assertEquals((16 + i) << 3, SyslogAppender.getFacility(names[i]));
185     }
186   }
187 
188   /***
189    * Test setFacilityPrinting.
190    */
191   public void testSetFacilityPrinting() {
192     SyslogAppender appender = new SyslogAppender();
193     assertFalse(appender.getFacilityPrinting());
194     appender.setFacilityPrinting(true);
195     assertTrue(appender.getFacilityPrinting());
196     appender.setFacilityPrinting(false);
197     assertFalse(appender.getFacilityPrinting());
198   }
199 
200   /***
201    * Test of SyslogAppender constants.
202    */
203   public void testConstants() {
204     assertEquals(0 << 3, SyslogAppender.LOG_KERN);
205     assertEquals(1 << 3, SyslogAppender.LOG_USER);
206     assertEquals(2 << 3, SyslogAppender.LOG_MAIL);
207     assertEquals(3 << 3, SyslogAppender.LOG_DAEMON);
208     assertEquals(4 << 3, SyslogAppender.LOG_AUTH);
209     assertEquals(5 << 3, SyslogAppender.LOG_SYSLOG);
210     assertEquals(6 << 3, SyslogAppender.LOG_LPR);
211     assertEquals(7 << 3, SyslogAppender.LOG_NEWS);
212     assertEquals(8 << 3, SyslogAppender.LOG_UUCP);
213     assertEquals(9 << 3, SyslogAppender.LOG_CRON);
214     assertEquals(10 << 3, SyslogAppender.LOG_AUTHPRIV);
215     assertEquals(11 << 3, SyslogAppender.LOG_FTP);
216     assertEquals(16 << 3, SyslogAppender.LOG_LOCAL0);
217     assertEquals(17 << 3, SyslogAppender.LOG_LOCAL1);
218     assertEquals(18 << 3, SyslogAppender.LOG_LOCAL2);
219     assertEquals(19 << 3, SyslogAppender.LOG_LOCAL3);
220     assertEquals(20 << 3, SyslogAppender.LOG_LOCAL4);
221     assertEquals(21 << 3, SyslogAppender.LOG_LOCAL5);
222     assertEquals(22 << 3, SyslogAppender.LOG_LOCAL6);
223     assertEquals(23 << 3, SyslogAppender.LOG_LOCAL7);
224   }
225 
226   /***
227    * Test setFacility with null.
228    * Should have no effect.
229    */
230   public void testSetFacilityKern() {
231     SyslogAppender appender = new SyslogAppender();
232     appender.setFacility("kern");
233     appender.setFacility(null);
234     assertEquals("kern", appender.getFacility());
235   }
236 
237   /***
238    * Test setFacility with null.
239    * Should have no effect.
240    */
241   public void testSetFacilityNull() {
242     SyslogAppender appender = new SyslogAppender();
243     appender.setFacility("kern");
244     appender.setFacility(null);
245     assertEquals("kern", appender.getFacility());
246   }
247 
248   /***
249    * Test setFacility with bogus value.
250    * Should reset to user.
251    */
252   public void testSetFacilityBogus() {
253     SyslogAppender appender = new SyslogAppender();
254     appender.setFacility("kern");
255     appender.setFacility("bogus");
256     assertEquals("user", appender.getFacility());
257   }
258 
259   /***
260    * Tests calling setFacility after appender has been activated.
261    */
262   public void testSetFacilityAfterActivation() {
263     SyslogAppender appender = new SyslogAppender();
264     appender.setName("foo");
265     appender.setThreshold(Level.INFO);
266     appender.setSyslogHost("localhost");
267     appender.setFacility("user");
268     appender.setLayout(new PatternLayout("%m%n"));
269 
270     VectorErrorHandler errorHandler = new VectorErrorHandler();
271     appender.setErrorHandler(errorHandler);
272     appender.activateOptions();
273     appender.setFacility("kern");
274     assertEquals("kern", appender.getFacility());
275   }
276 
277   /***
278    * Tests that append method drops messages below threshold.
279    * Can't reach isSevereAsThreshold call in SyslogAppender.append
280    * since it is checked in AppenderSkeleton.doAppend.
281    */
282   public void testAppendBelowThreshold() {
283     SyslogAppender appender = new SyslogAppender();
284     appender.setThreshold(Level.ERROR);
285     appender.activateOptions();
286 
287     Logger logger = Logger.getRootLogger();
288     logger.addAppender(appender);
289     logger.info(
290       "Should not be logged by SyslogAppenderTest.testAppendBelowThreshold.");
291   }
292 
293   /***
294    * Tests that append method drops messages below threshold.
295    */
296   public void testAppendNoHost() {
297     SyslogAppender appender = new SyslogAppender();
298     appender.setName("foo");
299     appender.setThreshold(Level.INFO);
300 
301     VectorErrorHandler errorHandler = new VectorErrorHandler();
302     appender.setErrorHandler(errorHandler);
303     appender.setLayout(new PatternLayout("%m%n"));
304     appender.activateOptions();
305 
306     Logger logger = Logger.getRootLogger();
307     logger.addAppender(appender);
308     logger.info(
309       "Should not be logged by SyslogAppenderTest.testAppendNoHost.");
310     assertEquals(1, errorHandler.size());
311 
312     //
313     //  Appender is misspelled in implementation
314     //
315     assertEquals(
316       "No syslog host is set for SyslogAppedender named \"foo\".",
317       errorHandler.getMessage(0));
318   }
319 
320   /***
321    * Tests append method under normal conditions.
322    */
323   public void testAppend() {
324     SyslogAppender appender = new SyslogAppender();
325     appender.setName("foo");
326     appender.setThreshold(Level.INFO);
327     appender.setSyslogHost("localhost");
328     appender.setFacility("user");
329     appender.setLayout(new PatternLayout("%m%n"));
330 
331     VectorErrorHandler errorHandler = new VectorErrorHandler();
332     appender.setErrorHandler(errorHandler);
333     appender.activateOptions();
334 
335     //
336     //  wrap SyslogAppender with an Async since appender may
337     //    hang if syslogd is not accepting network messages
338     //
339     AsyncAppender asyncAppender = new AsyncAppender();
340     asyncAppender.addAppender(appender);
341     asyncAppender.activateOptions();
342 
343     Logger logger = Logger.getRootLogger();
344     logger.addAppender(asyncAppender);
345 
346     Exception e =
347       new Exception("Expected exception from SyslogAppenderTest.testAppend");
348     logger.info(
349       "Expected message from log4j unit test SyslogAppenderTest.testAppend.", e);
350     assertEquals(0, errorHandler.size());
351   }
352 
353   /***
354     *  Tests SyslogAppender with IPv6 address.
355     */
356   public void testIPv6() {
357       SyslogAppender appender = new SyslogAppender();
358       appender.setSyslogHost("::1");
359   }
360 
361   /***
362     *  Tests SyslogAppender with IPv6 address enclosed in square brackets.
363     */
364   public void testIPv6InBrackets() {
365       SyslogAppender appender = new SyslogAppender();
366       appender.setSyslogHost("[::1]");
367   }
368 
369   /***
370     *  Tests SyslogAppender with IPv6 address enclosed in square brackets
371     *     followed by port specification.
372     */
373   public void testIPv6AndPort() {
374       SyslogAppender appender = new SyslogAppender();
375       appender.setSyslogHost("[::1]:1514");
376   }
377 
378   /***
379     *  Tests SyslogAppender with host name enclosed in square brackets
380     *     followed by port specification.
381     */
382   public void testHostNameAndPort() {
383       SyslogAppender appender = new SyslogAppender();
384       appender.setSyslogHost("localhost:1514");
385   }
386 
387 
388   /***
389     *  Tests SyslogAppender with IPv4 address followed by port specification.
390     */
391   public void testIPv4AndPort() {
392       SyslogAppender appender = new SyslogAppender();
393       appender.setSyslogHost("127.0.0.1:1514");
394   }
395 
396     private static String[] log(final boolean header,
397                                 final String msg,
398                                 final Exception ex,
399                                 final int packets) throws Exception {
400         DatagramSocket ds = new DatagramSocket();
401         ds.setSoTimeout(2000);
402 
403       SyslogAppender appender = new SyslogAppender();
404       appender.setSyslogHost("localhost:" + ds.getLocalPort());
405       appender.setName("name");
406       appender.setHeader(header);
407       PatternLayout pl = new PatternLayout("%m");
408       appender.setLayout(pl);
409       appender.activateOptions();
410 
411       Logger l = Logger.getRootLogger();
412       l.addAppender(appender);
413       if (ex == null) {
414         l.info(msg);
415       } else {
416         l.error(msg, ex);
417       }
418       appender.close();
419       String[] retval = new String[packets];
420       byte[] buf = new byte[1000];
421       for(int i = 0; i < packets; i++) {
422           DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
423           ds.receive(p);
424           retval[i] = new String(p.getData(), 0, p.getLength());
425       }
426       ds.close();
427       return retval;
428     }
429 
430     public void testActualLogging() throws Exception {
431       String s = log(false, "greetings", null, 1)[0];
432       StringTokenizer st = new StringTokenizer(s, "<>() ");
433       assertEquals("14", st.nextToken());
434       assertEquals("greetings", st.nextToken());
435     }
436 
437     /***
438      * Exception with printStackTrace that breaks earlier SyslogAppender.
439      */
440     private static class MishandledException extends Exception {
441         /*
442          *   Create new instance.
443          */
444         public MishandledException() {
445         }
446 
447         /***
448          * Print stack trace.
449          * @param w print writer, may not be null.
450          */
451         public void printStackTrace(final java.io.PrintWriter w) {
452              w.println("Mishandled stack trace follows:");
453              w.println("");
454              w.println("No tab here");
455              w.println("\ttab here");
456              w.println("\t");
457         }
458     }
459 
460     /***
461      * Tests fix for bug 40502.
462      * @throws Exception on IOException.
463      */
464     public void testBadTabbing() throws Exception {
465         String[] s = log(false, "greetings", new MishandledException(), 6);
466         StringTokenizer st = new StringTokenizer(s[0], "<>() ");
467         assertEquals("11", st.nextToken());
468         assertEquals("greetings", st.nextToken());
469         assertEquals("<11>Mishandled stack trace follows:", s[1]);
470         assertEquals("<11>", s[2]);
471         assertEquals("<11>No tab here", s[3]);
472         assertEquals("<11>" + SyslogAppender.TAB + "tab here", s[4]);
473         assertEquals("<11>" + SyslogAppender.TAB, s[5]);
474     }
475 
476     /***
477      * Tests presence of timestamp if header = true.
478      *
479      * @throws Exception if IOException.
480      */
481     public void testHeaderLogging() throws Exception {
482       Date preDate = new Date();
483       String s = log(true, "greetings", null, 1)[0];
484       Date postDate = new Date();
485       assertEquals("<14>", s.substring(0, 4));
486 
487       String syslogDateStr = s.substring(4, 20);
488       SimpleDateFormat fmt = new SimpleDateFormat("MMM dd HH:mm:ss ", Locale.ENGLISH);
489       Date syslogDate = fmt.parse(syslogDateStr);
490       Calendar cal = Calendar.getInstance(Locale.ENGLISH);
491       cal.setTime(syslogDate);
492       int syslogMonth = cal.get(Calendar.MONTH);
493       int syslogDay = cal.get(Calendar.DATE);
494       if (syslogDay < 10) {
495           assertEquals(' ', syslogDateStr.charAt(4));
496       }
497       cal.setTime(preDate);
498       int preMonth = cal.get(Calendar.MONTH);
499       cal.set(Calendar.MILLISECOND, 0);
500       preDate = cal.getTime();
501       int syslogYear;
502       if (preMonth == syslogMonth) {
503           syslogYear = cal.get(Calendar.YEAR);
504       } else {
505           cal.setTime(postDate);
506           syslogYear = cal.get(Calendar.YEAR);
507       }
508       cal.setTime(syslogDate);
509       cal.set(Calendar.YEAR, syslogYear);
510       syslogDate = cal.getTime();
511       assertTrue(syslogDate.compareTo(preDate) >= 0);
512       assertTrue(syslogDate.compareTo(postDate) <= 0);
513     }
514 
515 
516     /***
517      * Tests that any header or footer in layout is sent.
518      * @throws Exception if exception during test.
519      */
520     public void testLayoutHeader() throws Exception {
521         DatagramSocket ds = new DatagramSocket();
522         ds.setSoTimeout(2000);
523 
524       SyslogAppender appender = new SyslogAppender();
525       appender.setSyslogHost("localhost:" + ds.getLocalPort());
526       appender.setName("name");
527       appender.setHeader(false);
528       HTMLLayout pl = new HTMLLayout();
529       appender.setLayout(pl);
530       appender.activateOptions();
531 
532       Logger l = Logger.getRootLogger();
533       l.addAppender(appender);
534       l.info("Hello, World");
535       appender.close();
536       String[] s = new String[3];
537       byte[] buf = new byte[1000];
538       for(int i = 0; i < 3; i++) {
539           DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
540           ds.receive(p);
541           s[i] = new String(p.getData(), 0, p.getLength());
542       }
543       ds.close();
544       assertEquals("<14><!DOCTYPE", s[0].substring(0,13));
545       assertEquals("<14></table>", s[2].substring(0,12));
546     }
547 
548     /***
549      * Tests that syslog packets do not exceed 1024 bytes.
550      * See bug 42087.
551      * @throws Exception if exception during test.
552      */
553     public void testBigPackets() throws Exception {
554         DatagramSocket ds = new DatagramSocket();
555         ds.setSoTimeout(2000);
556 
557       SyslogAppender appender = new SyslogAppender();
558       appender.setSyslogHost("localhost:" + ds.getLocalPort());
559       appender.setName("name");
560       appender.setHeader(false);
561       PatternLayout pl = new PatternLayout("%m");
562       appender.setLayout(pl);
563       appender.activateOptions();
564 
565       Logger l = Logger.getRootLogger();
566       l.addAppender(appender);
567       StringBuffer msgbuf = new StringBuffer();
568       while(msgbuf.length() < 8000) {
569           msgbuf.append("0123456789");
570       }
571       String msg = msgbuf.toString();
572       l.info(msg);
573       appender.close();
574       String[] s = new String[8];
575       byte[] buf = new byte[1200];
576       for(int i = 0; i < 8; i++) {
577           DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
578           ds.receive(p);
579           assertTrue(p.getLength() <= 1024);
580           s[i] = new String(p.getData(), 0, p.getLength());
581       }
582       ds.close();
583       StringBuffer rcvbuf = new StringBuffer(s[0]);
584       rcvbuf.delete(0, 4);
585       for(int i = 1; i < 8; i++) {
586           rcvbuf.setLength(rcvbuf.length() - 3);
587           rcvbuf.append(s[i].substring(s[i].indexOf("...") + 3));
588       }
589       assertEquals(msg.length(), rcvbuf.length());
590       assertEquals(msg, rcvbuf.toString());
591     }
592 
593 }