/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.net;
import junit.framework.TestCase;
import org.apache.log4j.AsyncAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.VectorErrorHandler;
import org.apache.log4j.HTMLLayout;
import java.util.StringTokenizer;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Date;
import java.util.Calendar;
/**
* Tests for SyslogAppender
*
*
* */
public class SyslogAppenderTest extends TestCase {
/**
* Create new instance of SyslogAppenderTest.
* @param testName test name
*/
public SyslogAppenderTest(final String testName) {
super(testName);
}
/**
* Resets configuration after every test.
*/
public void tearDown() {
LogManager.resetConfiguration();
}
/**
* Test default constructor.
*/
public void testDefaultConstructor() {
SyslogAppender appender = new SyslogAppender();
assertEquals("user", appender.getFacility());
assertEquals(false, appender.getFacilityPrinting());
assertNull(appender.getLayout());
assertNull(appender.getSyslogHost());
assertNull(appender.getTag());
assertTrue(appender.requiresLayout());
}
/**
* Test two parameter constructor.
*/
public void testTwoParamConstructor() {
Layout layout = new PatternLayout();
SyslogAppender appender = new SyslogAppender(layout, 24);
assertEquals("daemon", appender.getFacility());
assertEquals(false, appender.getFacilityPrinting());
assertEquals(layout, appender.getLayout());
assertNull(appender.getSyslogHost());
assertNull(appender.getTag());
assertTrue(appender.requiresLayout());
}
/**
* Test two parameter constructor with unexpected facility.
*/
public void testTwoParamConstructorBadFacility() {
Layout layout = new PatternLayout();
SyslogAppender appender = new SyslogAppender(layout, 25);
assertEquals("user", appender.getFacility());
assertEquals(false, appender.getFacilityPrinting());
assertEquals(layout, appender.getLayout());
assertNull(appender.getSyslogHost());
assertNull(appender.getTag());
assertTrue(appender.requiresLayout());
}
/**
* Test three parameter constructor.
*/
public void testThreeParamConstructor() {
Layout layout = new PatternLayout();
SyslogAppender appender =
new SyslogAppender(layout, "syslog.example.org", 24);
assertEquals("daemon", appender.getFacility());
assertEquals(false, appender.getFacilityPrinting());
assertEquals(layout, appender.getLayout());
assertEquals("syslog.example.org", appender.getSyslogHost());
assertNull(appender.getTag());
assertTrue(appender.requiresLayout());
}
/**
* Test getFacilityString for expected facility codes.
*/
public void testGetFacilityString() {
String expected =
"kern user mail daemon auth syslog lpr news "
+ "uucp cron authpriv ftp local0 local1 local2 local3 "
+ "local4 local5 local6 local7 ";
StringBuffer actual = new StringBuffer();
for (int i = 0; i <= 11; i++) {
actual.append(SyslogAppender.getFacilityString(i << 3));
actual.append(' ');
}
for (int i = 16; i <= 23; i++) {
actual.append(SyslogAppender.getFacilityString(i << 3));
actual.append(' ');
}
assertEquals(expected, actual.toString());
}
/**
* Test getFacilityString for some unexpected facility codes.
*/
public void testGetFacilityStringUnexpected() {
assertNull(SyslogAppender.getFacilityString(1));
assertNull(SyslogAppender.getFacilityString(12 << 3));
}
/**
* Test getFacility with a bogus facility name.
*/
public void testGetFacilityBogus() {
assertEquals(-1, SyslogAppender.getFacility("bogus"));
}
/**
* Test getFacility with a null facility name.
*/
public void testGetFacilityNull() {
assertEquals(-1, SyslogAppender.getFacility(null));
}
/**
* Test getFacility for expected system facility names.
*/
public void testGetFacilitySystemNames() {
String[] names =
new String[] {
"kErn", "usEr", "MaIL", "daemOn", "auTh", "syslOg", "lPr", "newS",
"Uucp", "croN", "authprIv", "ftP"
};
for (int i = 0; i <= 11; i++) {
assertEquals(i << 3, SyslogAppender.getFacility(names[i]));
}
}
/**
* Test getFacility for expected system facility names.
*/
public void testGetFacilityLocalNames() {
String[] names =
new String[] {
"lOcal0", "LOCAL1", "loCal2", "locAl3", "locaL4", "local5", "LOCal6",
"loCAL7"
};
for (int i = 0; i <= 7; i++) {
assertEquals((16 + i) << 3, SyslogAppender.getFacility(names[i]));
}
}
/**
* Test setFacilityPrinting.
*/
public void testSetFacilityPrinting() {
SyslogAppender appender = new SyslogAppender();
assertFalse(appender.getFacilityPrinting());
appender.setFacilityPrinting(true);
assertTrue(appender.getFacilityPrinting());
appender.setFacilityPrinting(false);
assertFalse(appender.getFacilityPrinting());
}
/**
* Test of SyslogAppender constants.
*/
public void testConstants() {
assertEquals(0 << 3, SyslogAppender.LOG_KERN);
assertEquals(1 << 3, SyslogAppender.LOG_USER);
assertEquals(2 << 3, SyslogAppender.LOG_MAIL);
assertEquals(3 << 3, SyslogAppender.LOG_DAEMON);
assertEquals(4 << 3, SyslogAppender.LOG_AUTH);
assertEquals(5 << 3, SyslogAppender.LOG_SYSLOG);
assertEquals(6 << 3, SyslogAppender.LOG_LPR);
assertEquals(7 << 3, SyslogAppender.LOG_NEWS);
assertEquals(8 << 3, SyslogAppender.LOG_UUCP);
assertEquals(9 << 3, SyslogAppender.LOG_CRON);
assertEquals(10 << 3, SyslogAppender.LOG_AUTHPRIV);
assertEquals(11 << 3, SyslogAppender.LOG_FTP);
assertEquals(16 << 3, SyslogAppender.LOG_LOCAL0);
assertEquals(17 << 3, SyslogAppender.LOG_LOCAL1);
assertEquals(18 << 3, SyslogAppender.LOG_LOCAL2);
assertEquals(19 << 3, SyslogAppender.LOG_LOCAL3);
assertEquals(20 << 3, SyslogAppender.LOG_LOCAL4);
assertEquals(21 << 3, SyslogAppender.LOG_LOCAL5);
assertEquals(22 << 3, SyslogAppender.LOG_LOCAL6);
assertEquals(23 << 3, SyslogAppender.LOG_LOCAL7);
}
/**
* Test setFacility with null.
* Should have no effect.
*/
public void testSetFacilityKern() {
SyslogAppender appender = new SyslogAppender();
appender.setFacility("kern");
appender.setFacility(null);
assertEquals("kern", appender.getFacility());
}
/**
* Test setFacility with null.
* Should have no effect.
*/
public void testSetFacilityNull() {
SyslogAppender appender = new SyslogAppender();
appender.setFacility("kern");
appender.setFacility(null);
assertEquals("kern", appender.getFacility());
}
/**
* Test setFacility with bogus value.
* Should reset to user.
*/
public void testSetFacilityBogus() {
SyslogAppender appender = new SyslogAppender();
appender.setFacility("kern");
appender.setFacility("bogus");
assertEquals("user", appender.getFacility());
}
/**
* Tests calling setFacility after appender has been activated.
*/
public void testSetFacilityAfterActivation() {
SyslogAppender appender = new SyslogAppender();
appender.setName("foo");
appender.setThreshold(Level.INFO);
appender.setSyslogHost("localhost");
appender.setFacility("user");
appender.setLayout(new PatternLayout("%m%n"));
VectorErrorHandler errorHandler = new VectorErrorHandler();
appender.setErrorHandler(errorHandler);
appender.activateOptions();
appender.setFacility("kern");
assertEquals("kern", appender.getFacility());
}
/**
* Tests that append method drops messages below threshold.
* Can't reach isSevereAsThreshold call in SyslogAppender.append
* since it is checked in AppenderSkeleton.doAppend.
*/
public void testAppendBelowThreshold() {
SyslogAppender appender = new SyslogAppender();
appender.setThreshold(Level.ERROR);
appender.activateOptions();
Logger logger = Logger.getRootLogger();
logger.addAppender(appender);
logger.info(
"Should not be logged by SyslogAppenderTest.testAppendBelowThreshold.");
}
/**
* Tests that append method drops messages below threshold.
*/
public void testAppendNoHost() {
SyslogAppender appender = new SyslogAppender();
appender.setName("foo");
appender.setThreshold(Level.INFO);
VectorErrorHandler errorHandler = new VectorErrorHandler();
appender.setErrorHandler(errorHandler);
appender.setLayout(new PatternLayout("%m%n"));
appender.activateOptions();
Logger logger = Logger.getRootLogger();
logger.addAppender(appender);
logger.info(
"Should not be logged by SyslogAppenderTest.testAppendNoHost.");
assertEquals(1, errorHandler.size());
//
// Appender is misspelled in implementation
//
assertEquals(
"No syslog host is set for SyslogAppedender named \"foo\".",
errorHandler.getMessage(0));
}
/**
* Tests append method under normal conditions.
*/
public void testAppend() {
SyslogAppender appender = new SyslogAppender();
appender.setName("foo");
appender.setThreshold(Level.INFO);
appender.setSyslogHost("localhost");
appender.setFacility("user");
appender.setLayout(new PatternLayout("%m%n"));
VectorErrorHandler errorHandler = new VectorErrorHandler();
appender.setErrorHandler(errorHandler);
appender.activateOptions();
//
// wrap SyslogAppender with an Async since appender may
// hang if syslogd is not accepting network messages
//
AsyncAppender asyncAppender = new AsyncAppender();
asyncAppender.addAppender(appender);
asyncAppender.activateOptions();
Logger logger = Logger.getRootLogger();
logger.addAppender(asyncAppender);
Exception e =
new Exception("Expected exception from SyslogAppenderTest.testAppend");
logger.info(
"Expected message from log4j unit test SyslogAppenderTest.testAppend.", e);
assertEquals(0, errorHandler.size());
}
/**
* Tests SyslogAppender with IPv6 address.
*/
public void testIPv6() {
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("::1");
}
/**
* Tests SyslogAppender with IPv6 address enclosed in square brackets.
*/
public void testIPv6InBrackets() {
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("[::1]");
}
/**
* Tests SyslogAppender with IPv6 address enclosed in square brackets
* followed by port specification.
*/
public void testIPv6AndPort() {
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("[::1]:1514");
}
/**
* Tests SyslogAppender with host name enclosed in square brackets
* followed by port specification.
*/
public void testHostNameAndPort() {
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("localhost:1514");
}
/**
* Tests SyslogAppender with IPv4 address followed by port specification.
*/
public void testIPv4AndPort() {
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("127.0.0.1:1514");
}
/**
* Tests SyslogAppender with setTag.
*/
public void testTag() {
SyslogAppender appender = new SyslogAppender();
appender.setTag("testtag");
assertEquals("testtag", appender.getTag());
}
/**
* Tests SyslogAppender with null tag.
*/
public void testNullTag() {
SyslogAppender appender = new SyslogAppender();
appender.setTag(null);
assertNull(appender.getTag());
}
/**
* Tests SyslogAppender with long tag.
*/
public void testLongTag() {
SyslogAppender appender = new SyslogAppender();
appender.setTag("testtagtesttagtesttagtesttagtesttag");
assertEquals(appender.getTag(), "testtagtesttagtesttagtesttagtest");
}
/**
* Tests SyslogAppender with non alnum tag.
*/
public void testNonAlnumTag() {
SyslogAppender appender = new SyslogAppender();
try{
appender.setTag("testtag testtag");
fail("SyslogAppender.setTag() should have thrown an exception.");
} catch (IllegalArgumentException e) {
// Correct behavior, ignore and let the test pass.
}
}
private static String[] log(final boolean header,
final String tag,
final String msg,
final Exception ex,
final int packets) throws Exception {
DatagramSocket ds = new DatagramSocket();
ds.setSoTimeout(2000);
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("localhost:" + ds.getLocalPort());
appender.setName("name");
appender.setHeader(header);
appender.setTag(tag);
PatternLayout pl = new PatternLayout("%m");
appender.setLayout(pl);
appender.activateOptions();
Logger l = Logger.getRootLogger();
l.addAppender(appender);
if (ex == null) {
l.info(msg);
} else {
l.error(msg, ex);
}
appender.close();
String[] retval = new String[packets];
byte[] buf = new byte[1000];
for(int i = 0; i < packets; i++) {
DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
ds.receive(p);
retval[i] = new String(p.getData(), 0, p.getLength());
}
ds.close();
return retval;
}
public void testActualLogging() throws Exception {
String s = log(false, null, "greetings", null, 1)[0];
StringTokenizer st = new StringTokenizer(s, "<>() ");
assertEquals("14", st.nextToken());
assertEquals("greetings", st.nextToken());
}
/**
* Exception with printStackTrace that breaks earlier SyslogAppender.
*/
private static class MishandledException extends Exception {
private static final long serialVersionUID = 1L;
/*
* Create new instance.
*/
public MishandledException() {
}
/**
* Print stack trace.
* @param w print writer, may not be null.
*/
public void printStackTrace(final java.io.PrintWriter w) {
w.println("Mishandled stack trace follows:");
w.println("");
w.println("No tab here");
w.println("\ttab here");
w.println("\t");
}
}
/**
* Tests fix for bug 40502.
* @throws Exception on IOException.
*/
public void testBadTabbing() throws Exception {
String[] s = log(false, null, "greetings", new MishandledException(), 6);
StringTokenizer st = new StringTokenizer(s[0], "<>() ");
assertEquals("11", st.nextToken());
assertEquals("greetings", st.nextToken());
assertEquals("<11>Mishandled stack trace follows:", s[1]);
assertEquals("<11>", s[2]);
assertEquals("<11>No tab here", s[3]);
assertEquals("<11>" + SyslogAppender.TAB + "tab here", s[4]);
assertEquals("<11>" + SyslogAppender.TAB, s[5]);
}
/**
* Tests presence of timestamp if header = true.
*
* @throws Exception if IOException.
*/
public void testHeaderLogging() throws Exception {
Date preDate = new Date();
String s = log(true, null, "greetings", null, 1)[0];
Date postDate = new Date();
assertEquals("<14>", s.substring(0, 4));
String syslogDateStr = s.substring(4, 20);
SimpleDateFormat fmt = new SimpleDateFormat("MMM dd HH:mm:ss ", Locale.ENGLISH);
Date syslogDate = fmt.parse(syslogDateStr);
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
cal.setTime(syslogDate);
int syslogMonth = cal.get(Calendar.MONTH);
int syslogDay = cal.get(Calendar.DATE);
if (syslogDay < 10) {
assertEquals(' ', syslogDateStr.charAt(4));
}
cal.setTime(preDate);
int preMonth = cal.get(Calendar.MONTH);
cal.set(Calendar.MILLISECOND, 0);
preDate = cal.getTime();
int syslogYear;
if (preMonth == syslogMonth) {
syslogYear = cal.get(Calendar.YEAR);
} else {
cal.setTime(postDate);
syslogYear = cal.get(Calendar.YEAR);
}
cal.setTime(syslogDate);
cal.set(Calendar.YEAR, syslogYear);
syslogDate = cal.getTime();
assertTrue(syslogDate.compareTo(preDate) >= 0);
assertTrue(syslogDate.compareTo(postDate) <= 0);
}
/**
* Tests presence of tag if set
*/
public void testHeaderTagLogging() throws Exception {
String s = log(true, "testtag", "greetings", null, 1)[0];
assertEquals("<14>", s.substring(0, 4));
StringTokenizer st = new StringTokenizer(s.substring(21), " ");
// Throw away the hostname
st.nextToken();
assertEquals("testtag:", st.nextToken());
}
/**
* Tests presence of tag on every line of the exception
*/
public void testHeaderTagExceptionLogging() throws Exception {
String[] s = log(true, "testtag", "greetings", new Exception(), 6);
for(int i=0; i < s.length; i++) {
System.err.println(s[i]);
assertEquals("<11>", s[i].substring(0, 4));
StringTokenizer st = new StringTokenizer(s[i].substring(21), " ");
// Throw away the hostname
st.nextToken();
assertEquals("testtag:", st.nextToken());
}
}
/**
* Tests absesence of tag if set to null
*/
public void testHeaderNullTagLogging() throws Exception {
String s = log(true, null, "greetings", null, 1)[0];
assertEquals("<14>", s.substring(0, 4));
StringTokenizer st = new StringTokenizer(s.substring(21), " ");
// Throw away the hostname
st.nextToken();
assertEquals("greetings", st.nextToken());
}
/**
* Tests that any header or footer in layout is sent.
* @throws Exception if exception during test.
*/
public void testLayoutHeader() throws Exception {
DatagramSocket ds = new DatagramSocket();
ds.setSoTimeout(2000);
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("localhost:" + ds.getLocalPort());
appender.setName("name");
appender.setHeader(false);
HTMLLayout pl = new HTMLLayout();
appender.setLayout(pl);
appender.activateOptions();
Logger l = Logger.getRootLogger();
l.addAppender(appender);
l.info("Hello, World");
appender.close();
String[] s = new String[3];
byte[] buf = new byte[1000];
for(int i = 0; i < 3; i++) {
DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
ds.receive(p);
s[i] = new String(p.getData(), 0, p.getLength());
}
ds.close();
assertEquals("<14><!DOCTYPE", s[0].substring(0,13));
assertEquals("<14></table>", s[2].substring(0,12));
}
/**
* Tests that syslog packets do not exceed 1024 bytes.
* See bug 42087.
* @throws Exception if exception during test.
*/
public void testBigPackets() throws Exception {
DatagramSocket ds = new DatagramSocket();
ds.setSoTimeout(2000);
SyslogAppender appender = new SyslogAppender();
appender.setSyslogHost("localhost:" + ds.getLocalPort());
appender.setName("name");
appender.setHeader(false);
PatternLayout pl = new PatternLayout("%m");
appender.setLayout(pl);
appender.activateOptions();
Logger l = Logger.getRootLogger();
l.addAppender(appender);
StringBuffer msgbuf = new StringBuffer();
while(msgbuf.length() < 8000) {
msgbuf.append("0123456789");
}
String msg = msgbuf.toString();
l.info(msg);
appender.close();
String[] s = new String[8];
byte[] buf = new byte[1200];
for(int i = 0; i < 8; i++) {
DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
ds.receive(p);
assertTrue(p.getLength() <= 1024);
s[i] = new String(p.getData(), 0, p.getLength());
}
ds.close();
StringBuffer rcvbuf = new StringBuffer(s[0]);
rcvbuf.delete(0, 4);
for(int i = 1; i < 8; i++) {
rcvbuf.setLength(rcvbuf.length() - 3);
rcvbuf.append(s[i].substring(s[i].indexOf("...") + 3));
}
assertEquals(msg.length(), rcvbuf.length());
assertEquals(msg, rcvbuf.toString());
}
}