001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.net;
015
016import static org.junit.Assert.assertEquals;
017import static org.junit.Assert.assertTrue;
018
019import org.junit.After;
020import org.junit.Before;
021import org.junit.Ignore;
022import org.junit.Test;
023import org.slf4j.LoggerFactory;
024
025import ch.qos.logback.classic.ClassicTestConstants;
026import ch.qos.logback.classic.Logger;
027import ch.qos.logback.classic.LoggerContext;
028import ch.qos.logback.classic.joran.JoranConfigurator;
029import ch.qos.logback.classic.net.mock.MockSyslogServer;
030import ch.qos.logback.core.CoreConstants;
031import ch.qos.logback.core.joran.spi.JoranException;
032import ch.qos.logback.core.net.SyslogConstants;
033import ch.qos.logback.core.recovery.RecoveryCoordinator;
034import ch.qos.logback.core.testUtil.RandomUtil;
035import ch.qos.logback.core.util.StatusPrinter;
036
037import java.nio.charset.Charset;
038@Ignore
039public class SyslogAppenderTest {
040
041    private static final String SYSLOG_PREFIX_REGEX = "<\\d{2}>\\w{3} [\\d ]\\d \\d{2}(:\\d{2}){2} [\\w.-]* ";
042
043    LoggerContext lc = new LoggerContext();
044    SyslogAppender sa = new SyslogAppender();
045    MockSyslogServer mockServer;
046    String loggerName = this.getClass().getName();
047    Logger logger = lc.getLogger(loggerName);
048
049    @Before
050    public void setUp() throws Exception {
051        lc.setName("test");
052        sa.setContext(lc);
053    }
054
055    @After
056    public void tearDown() throws Exception {
057    }
058
059    public void setMockServerAndConfigure(int expectedCount, String suffixPattern) throws InterruptedException {
060        int port = RandomUtil.getRandomServerPort();
061
062        mockServer = new MockSyslogServer(expectedCount, port);
063        mockServer.start();
064        // give MockSyslogServer head start
065
066        Thread.sleep(100);
067
068        sa.setSyslogHost("localhost");
069        sa.setFacility("MAIL");
070        sa.setPort(port);
071        sa.setSuffixPattern(suffixPattern);
072        sa.setStackTracePattern("[%thread] foo " + CoreConstants.TAB);
073        sa.start();
074        assertTrue(sa.isStarted());
075
076        String loggerName = this.getClass().getName();
077        Logger logger = lc.getLogger(loggerName);
078        logger.addAppender(sa);
079
080    }
081
082    public void setMockServerAndConfigure(int expectedCount) throws InterruptedException {
083        this.setMockServerAndConfigure(expectedCount, "[%thread] %logger %msg");
084    }
085
086    @Test
087    public void basic() throws InterruptedException {
088
089        setMockServerAndConfigure(1);
090        String logMsg = "hello";
091        logger.debug(logMsg);
092
093        // wait max 2 seconds for mock server to finish. However, it should
094        // much sooner than that.
095        mockServer.join(8000);
096
097        assertTrue(mockServer.isFinished());
098        assertEquals(1, mockServer.getMessageList().size());
099        String msg = new String(mockServer.getMessageList().get(0));
100
101        String threadName = Thread.currentThread().getName();
102
103        String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
104        assertTrue(msg.startsWith(expected));
105
106        checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
107
108    }
109
110    @Test
111    public void suffixPatternWithTag() throws InterruptedException {
112        setMockServerAndConfigure(1, "test/something [%thread] %logger %msg");
113        String logMsg = "hello";
114        logger.debug(logMsg);
115
116        // wait max 2 seconds for mock server to finish. However, it should
117        // much sooner than that.
118        mockServer.join(8000);
119
120        assertTrue(mockServer.isFinished());
121        assertEquals(1, mockServer.getMessageList().size());
122        String msg = new String(mockServer.getMessageList().get(0));
123
124        String threadName = Thread.currentThread().getName();
125
126        String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
127        assertTrue(msg.startsWith(expected));
128
129        checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "test/something \\[" + threadName + "\\] " + loggerName + " " + logMsg);
130
131    }
132
133    @Test
134    public void tException() throws InterruptedException {
135        setMockServerAndConfigure(21);
136
137        String logMsg = "hello";
138        String exMsg = "just testing";
139        Exception ex = new Exception(exMsg);
140        logger.debug(logMsg, ex);
141        StatusPrinter.print(lc);
142
143        // wait max 2 seconds for mock server to finish. However, it should
144        // much sooner than that.
145        mockServer.join(8000);
146        assertTrue(mockServer.isFinished());
147
148        // message + 20 lines of stacktrace
149        assertEquals(21, mockServer.getMessageList().size());
150        // int i = 0;
151        // for (String line: mockServer.msgList) {
152        // System.out.println(i++ + ": " + line);
153        // }
154
155        String msg = new String(mockServer.getMessageList().get(0));
156        String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
157        assertTrue(msg.startsWith(expected));
158
159        String threadName = Thread.currentThread().getName();
160        String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
161        checkRegexMatch(msg, regex);
162
163        msg = new String(mockServer.getMessageList().get(1));
164        assertTrue(msg.contains(ex.getClass().getName()));
165        assertTrue(msg.contains(ex.getMessage()));
166
167        msg = new String(mockServer.getMessageList().get(2));
168        assertTrue(msg.startsWith(expected));
169        regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + "foo " + CoreConstants.TAB + "at ch\\.qos.*";
170        checkRegexMatch(msg, regex);
171    }
172
173    private void checkRegexMatch(String s, String regex) {
174        assertTrue("The string [" + s + "] did not match regex [" + regex + "]", s.matches(regex));
175    }
176
177    @Test
178    public void large() throws Exception {
179        setMockServerAndConfigure(2);
180        StringBuilder largeBuf = new StringBuilder();
181        for (int i = 0; i < 2 * 1024 * 1024; i++) {
182            largeBuf.append('a');
183        }
184        logger.debug(largeBuf.toString());
185
186        String logMsg = "hello";
187        logger.debug(logMsg);
188        Thread.sleep(RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN + 10);
189        logger.debug(logMsg);
190
191        mockServer.join(8000);
192        assertTrue(mockServer.isFinished());
193
194        // both messages received
195        assertEquals(2, mockServer.getMessageList().size());
196
197        String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
198        String threadName = Thread.currentThread().getName();
199
200        // large message is truncated
201        final int maxMessageSize = sa.getMaxMessageSize();
202        String largeMsg = new String(mockServer.getMessageList().get(0));
203        assertTrue(largeMsg.startsWith(expected));
204        String largeRegex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + "a{" + (maxMessageSize - 2000) + "," + maxMessageSize + "}";
205        checkRegexMatch(largeMsg, largeRegex);
206
207        String msg = new String(mockServer.getMessageList().get(1));
208        assertTrue(msg.startsWith(expected));
209        String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
210        checkRegexMatch(msg, regex);
211    }
212
213    @Test
214    public void LBCLASSIC_50() throws JoranException {
215
216        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
217
218        JoranConfigurator configurator = new JoranConfigurator();
219        configurator.setContext(lc);
220        lc.reset();
221        configurator.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "syslog_LBCLASSIC_50.xml");
222
223        org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());
224        logger.info("hello");
225    }
226
227    @Test
228    public void unknownHostShouldNotCauseStopToFail() {
229        // See LOGBACK-960
230        sa.setSyslogHost("unknown.host");
231        sa.setFacility("MAIL");
232        sa.start();
233        sa.stop();
234    }
235
236    @Test
237    public void nonAsciiMessageEncoding() throws Exception {
238        // See LOGBACK-732
239        setMockServerAndConfigure(1);
240
241        // Use a string that can be encoded in a somewhat odd encoding (ISO-8859-4) to minimize
242        // the probability of the encoding test to work by accident
243        String logMsg = "R\u0129ga"; // Riga spelled with the i having a tilda on top
244
245        Charset ISO_8859_4 = Charset.forName("ISO-8859-4");
246        sa.setCharset(ISO_8859_4);
247        logger.debug(logMsg);
248
249        // wait max 8 seconds for mock server to finish. However, it should
250        // be done much sooner than that.
251        mockServer.join(8000);
252
253        assertTrue(mockServer.isFinished());
254        assertEquals(1, mockServer.getMessageList().size());
255        String msg = new String(mockServer.getMessageList().get(0), ISO_8859_4);
256        String threadName = Thread.currentThread().getName();
257
258        String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
259        assertTrue(msg.startsWith(expected));
260
261        System.out.println(logMsg);
262        checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
263
264    }
265}