/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.ClassicTestConstants;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.net.mock.MockSyslogServer;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.net.SyslogConstants;
import ch.qos.logback.core.recovery.RecoveryCoordinator;
import ch.qos.logback.core.testUtil.RandomUtil;
import ch.qos.logback.core.util.StatusPrinter;
import java.nio.charset.Charset;
public class SyslogAppenderTest {
private static final String SYSLOG_PREFIX_REGEX = "<\\d{2}>\\w{3} [\\d ]\\d \\d{2}(:\\d{2}){2} [\\w.-]* ";
LoggerContext lc = new LoggerContext();
SyslogAppender sa = new SyslogAppender();
MockSyslogServer mockServer;
String loggerName = this.getClass().getName();
Logger logger = lc.getLogger(loggerName);
@Before
public void setUp() throws Exception {
lc.setName("test");
sa.setContext(lc);
}
@After
public void tearDown() throws Exception {
}
public void setMockServerAndConfigure(int expectedCount, String suffixPattern) throws InterruptedException {
int port = RandomUtil.getRandomServerPort();
mockServer = new MockSyslogServer(expectedCount, port);
mockServer.start();
// give MockSyslogServer head start
Thread.sleep(100);
sa.setSyslogHost("localhost");
sa.setFacility("MAIL");
sa.setPort(port);
sa.setSuffixPattern(suffixPattern);
sa.setStackTracePattern("[%thread] foo " + CoreConstants.TAB);
sa.start();
assertTrue(sa.isStarted());
String loggerName = this.getClass().getName();
Logger logger = lc.getLogger(loggerName);
logger.addAppender(sa);
}
public void setMockServerAndConfigure(int expectedCount) throws InterruptedException {
this.setMockServerAndConfigure(expectedCount, "[%thread] %logger %msg");
}
@Test
public void basic() throws InterruptedException {
setMockServerAndConfigure(1);
String logMsg = "hello";
logger.debug(logMsg);
// wait max 2 seconds for mock server to finish. However, it should
// much sooner than that.
mockServer.join(8000);
assertTrue(mockServer.isFinished());
assertEquals(1, mockServer.getMessageList().size());
String msg = new String(mockServer.getMessageList().get(0));
String threadName = Thread.currentThread().getName();
String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
assertTrue(msg.startsWith(expected));
checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
}
@Test
public void suffixPatternWithTag() throws InterruptedException {
setMockServerAndConfigure(1, "test/something [%thread] %logger %msg");
String logMsg = "hello";
logger.debug(logMsg);
// wait max 2 seconds for mock server to finish. However, it should
// much sooner than that.
mockServer.join(8000);
assertTrue(mockServer.isFinished());
assertEquals(1, mockServer.getMessageList().size());
String msg = new String(mockServer.getMessageList().get(0));
String threadName = Thread.currentThread().getName();
String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
assertTrue(msg.startsWith(expected));
checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "test/something \\[" + threadName + "\\] " + loggerName + " " + logMsg);
}
@Test
public void tException() throws InterruptedException {
setMockServerAndConfigure(21);
String logMsg = "hello";
String exMsg = "just testing";
Exception ex = new Exception(exMsg);
logger.debug(logMsg, ex);
StatusPrinter.print(lc);
// wait max 2 seconds for mock server to finish. However, it should
// much sooner than that.
mockServer.join(8000);
assertTrue(mockServer.isFinished());
// message + 20 lines of stacktrace
assertEquals(21, mockServer.getMessageList().size());
// int i = 0;
// for (String line: mockServer.msgList) {
// System.out.println(i++ + ": " + line);
// }
String msg = new String(mockServer.getMessageList().get(0));
String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
assertTrue(msg.startsWith(expected));
String threadName = Thread.currentThread().getName();
String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
checkRegexMatch(msg, regex);
msg = new String(mockServer.getMessageList().get(1));
assertTrue(msg.contains(ex.getClass().getName()));
assertTrue(msg.contains(ex.getMessage()));
msg = new String(mockServer.getMessageList().get(2));
assertTrue(msg.startsWith(expected));
regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + "foo " + CoreConstants.TAB + "at ch\\.qos.*";
checkRegexMatch(msg, regex);
}
private void checkRegexMatch(String s, String regex) {
assertTrue("The string [" + s + "] did not match regex [" + regex + "]", s.matches(regex));
}
@Test
public void large() throws Exception {
setMockServerAndConfigure(2);
StringBuilder largeBuf = new StringBuilder();
for (int i = 0; i < 2 * 1024 * 1024; i++) {
largeBuf.append('a');
}
logger.debug(largeBuf.toString());
String logMsg = "hello";
logger.debug(logMsg);
Thread.sleep(RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN + 10);
logger.debug(logMsg);
mockServer.join(8000);
assertTrue(mockServer.isFinished());
// both messages received
assertEquals(2, mockServer.getMessageList().size());
String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
String threadName = Thread.currentThread().getName();
// large message is truncated
final int maxMessageSize = sa.getMaxMessageSize();
String largeMsg = new String(mockServer.getMessageList().get(0));
assertTrue(largeMsg.startsWith(expected));
String largeRegex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + "a{" + (maxMessageSize - 2000) + "," + maxMessageSize + "}";
checkRegexMatch(largeMsg, largeRegex);
String msg = new String(mockServer.getMessageList().get(1));
assertTrue(msg.startsWith(expected));
String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
checkRegexMatch(msg, regex);
}
@Test
public void LBCLASSIC_50() throws JoranException {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
lc.reset();
configurator.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "syslog_LBCLASSIC_50.xml");
org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("hello");
}
@Test
public void unknownHostShouldNotCauseStopToFail() {
// See LOGBACK-960
sa.setSyslogHost("unknown.host");
sa.setFacility("MAIL");
sa.start();
sa.stop();
}
@Test
public void nonAsciiMessageEncoding() throws Exception {
// See LOGBACK-732
setMockServerAndConfigure(1);
// Use a string that can be encoded in a somewhat odd encoding (ISO-8859-4) to minimize
// the probability of the encoding test to work by accident
String logMsg = "R\u0129ga"; // Riga spelled with the i having a tilda on top
Charset ISO_8859_4 = Charset.forName("ISO-8859-4");
sa.setCharset(ISO_8859_4);
logger.debug(logMsg);
// wait max 8 seconds for mock server to finish. However, it should
// be done much sooner than that.
mockServer.join(8000);
assertTrue(mockServer.isFinished());
assertEquals(1, mockServer.getMessageList().size());
String msg = new String(mockServer.getMessageList().get(0), ISO_8859_4);
String threadName = Thread.currentThread().getName();
String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
assertTrue(msg.startsWith(expected));
System.out.println(logMsg);
checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
}
}