View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.net;
15  
16  import ch.qos.logback.classic.util.LogbackMDCAdapter;
17  import org.junit.jupiter.api.AfterEach;
18  import org.junit.jupiter.api.BeforeEach;
19  import org.junit.jupiter.api.Disabled;
20  import org.junit.jupiter.api.Test;
21  import org.slf4j.LoggerFactory;
22  
23  import ch.qos.logback.classic.ClassicTestConstants;
24  import ch.qos.logback.classic.Logger;
25  import ch.qos.logback.classic.LoggerContext;
26  import ch.qos.logback.classic.joran.JoranConfigurator;
27  import ch.qos.logback.classic.net.mock.MockSyslogServer;
28  import ch.qos.logback.core.CoreConstants;
29  import ch.qos.logback.core.joran.spi.JoranException;
30  import ch.qos.logback.core.net.SyslogConstants;
31  import ch.qos.logback.core.recovery.RecoveryCoordinator;
32  import ch.qos.logback.core.testUtil.RandomUtil;
33  import ch.qos.logback.core.util.StatusPrinter;
34  
35  import java.nio.charset.Charset;
36  
37  import static org.junit.jupiter.api.Assertions.assertEquals;
38  import static org.junit.jupiter.api.Assertions.assertTrue;
39  
40  public class SyslogAppenderTest {
41  
42      private static final String SYSLOG_PREFIX_REGEX = "<\\d{2}>\\w{3} [\\d ]\\d \\d{2}(:\\d{2}){2} [\\w.-]* ";
43  
44      LoggerContext lc = new LoggerContext();
45      LogbackMDCAdapter logbackMDCAdapter = new LogbackMDCAdapter();
46  
47      SyslogAppender sa = new SyslogAppender();
48      MockSyslogServer mockServer;
49      String loggerName = this.getClass().getName();
50      Logger logger = lc.getLogger(loggerName);
51  
52      @BeforeEach
53      public void setUp() throws Exception {
54          lc.setName("test");
55          lc.setMDCAdapter(logbackMDCAdapter);
56          sa.setContext(lc);
57      }
58  
59      @AfterEach
60      public void tearDown() throws Exception {
61      }
62  
63      public void setMockServerAndConfigure(int expectedCount, String suffixPattern) throws InterruptedException {
64          int port = RandomUtil.getRandomServerPort();
65  
66          mockServer = new MockSyslogServer(expectedCount, port);
67          mockServer.start();
68          // give MockSyslogServer head start
69  
70          Thread.sleep(100);
71  
72          sa.setSyslogHost("localhost");
73          sa.setFacility("MAIL");
74          sa.setPort(port);
75          sa.setSuffixPattern(suffixPattern);
76          sa.setStackTracePattern("[%thread] foo " + CoreConstants.TAB);
77          sa.start();
78          assertTrue(sa.isStarted());
79  
80          String loggerName = this.getClass().getName();
81          Logger logger = lc.getLogger(loggerName);
82          logger.addAppender(sa);
83  
84      }
85  
86      public void setMockServerAndConfigure(int expectedCount) throws InterruptedException {
87          this.setMockServerAndConfigure(expectedCount, "[%thread] %logger %msg");
88      }
89  
90      @Test
91      public void basic() throws InterruptedException {
92  
93          setMockServerAndConfigure(1);
94          String logMsg = "hello";
95          logger.debug(logMsg);
96  
97          // wait max 2 seconds for mock server to finish. However, it should
98          // much sooner than that.
99          mockServer.join(8000);
100 
101         assertTrue(mockServer.isFinished());
102         assertEquals(1, mockServer.getMessageList().size());
103         String msg = new String(mockServer.getMessageList().get(0));
104 
105         String threadName = Thread.currentThread().getName();
106 
107         String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
108         assertTrue(msg.startsWith(expected));
109 
110         checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
111 
112     }
113 
114     @Test
115     public void suffixPatternWithTag() throws InterruptedException {
116         setMockServerAndConfigure(1, "test/something [%thread] %logger %msg");
117         String logMsg = "hello";
118         logger.debug(logMsg);
119 
120         // wait max 2 seconds for mock server to finish. However, it should
121         // much sooner than that.
122         mockServer.join(8000);
123 
124         assertTrue(mockServer.isFinished());
125         assertEquals(1, mockServer.getMessageList().size());
126         String msg = new String(mockServer.getMessageList().get(0));
127 
128         String threadName = Thread.currentThread().getName();
129 
130         String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
131         assertTrue(msg.startsWith(expected));
132 
133         checkRegexMatch(msg,
134                 SYSLOG_PREFIX_REGEX + "test/something \\[" + threadName + "\\] " + loggerName + " " + logMsg);
135 
136     }
137 
138     @Test
139     public void tException() throws InterruptedException {
140         setMockServerAndConfigure(21);
141 
142         String logMsg = "hello";
143         String exMsg = "just testing";
144         Exception ex = new Exception(exMsg);
145         logger.debug(logMsg, ex);
146         StatusPrinter.print(lc);
147 
148         // wait max 2 seconds for mock server to finish. However, it should
149         // much sooner than that.
150         mockServer.join(8000);
151         assertTrue(mockServer.isFinished());
152 
153         // message + 20 lines of stacktrace
154         assertEquals(21, mockServer.getMessageList().size());
155         // int i = 0;
156         // for (String line: mockServer.msgList) {
157         // System.out.println(i++ + ": " + line);
158         // }
159 
160         String msg = new String(mockServer.getMessageList().get(0));
161         String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
162         assertTrue(msg.startsWith(expected));
163 
164         String threadName = Thread.currentThread().getName();
165         String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
166         checkRegexMatch(msg, regex);
167 
168         msg = new String(mockServer.getMessageList().get(1));
169         assertTrue(msg.contains(ex.getClass().getName()));
170         assertTrue(msg.contains(ex.getMessage()));
171 
172         msg = new String(mockServer.getMessageList().get(2));
173         assertTrue(msg.startsWith(expected));
174         regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + "foo " + CoreConstants.TAB + "at ch\\.qos.*";
175         checkRegexMatch(msg, regex);
176     }
177 
178     private void checkRegexMatch(String s, String regex) {
179         assertTrue(s.matches(regex), "The string [" + s + "] did not match regex [" + regex + "]");
180     }
181 
182     @Test
183     public void large() throws Exception {
184         setMockServerAndConfigure(2);
185         StringBuilder largeBuf = new StringBuilder();
186         for (int i = 0; i < 2 * 1024 * 1024; i++) {
187             largeBuf.append('a');
188         }
189         logger.debug(largeBuf.toString());
190 
191         String logMsg = "hello";
192         logger.debug(logMsg);
193         Thread.sleep(RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN + 10);
194         logger.debug(logMsg);
195 
196         mockServer.join(8000);
197         assertTrue(mockServer.isFinished());
198 
199         // both messages received
200         assertEquals(2, mockServer.getMessageList().size());
201 
202         String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
203         String threadName = Thread.currentThread().getName();
204 
205         // large message is truncated
206         final int maxMessageSize = sa.getMaxMessageSize();
207         String largeMsg = new String(mockServer.getMessageList().get(0));
208         assertTrue(largeMsg.startsWith(expected));
209         String largeRegex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + "a{"
210                 + (maxMessageSize - 2000) + "," + maxMessageSize + "}";
211         checkRegexMatch(largeMsg, largeRegex);
212 
213         String msg = new String(mockServer.getMessageList().get(1));
214         assertTrue(msg.startsWith(expected));
215         String regex = SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg;
216         checkRegexMatch(msg, regex);
217     }
218 
219     @Test
220     public void LBCLASSIC_50() throws JoranException {
221 
222         LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
223 
224         JoranConfigurator configurator = new JoranConfigurator();
225         configurator.setContext(lc);
226         lc.reset();
227         configurator.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "syslog_LBCLASSIC_50.xml");
228 
229         org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());
230         logger.info("hello");
231     }
232 
233     @Test
234     public void unknownHostShouldNotCauseStopToFail() {
235         // See LOGBACK-960
236         sa.setSyslogHost("unknown.host");
237         sa.setFacility("MAIL");
238         sa.start();
239         sa.stop();
240     }
241 
242     @Test
243     public void nonAsciiMessageEncoding() throws Exception {
244         // See LOGBACK-732
245         setMockServerAndConfigure(1);
246 
247         // Use a string that can be encoded in a somewhat odd encoding (ISO-8859-4) to
248         // minimize
249         // the probability of the encoding test to work by accident
250         String logMsg = "R\u0129ga"; // Riga spelled with the i having a tilda on top
251 
252         Charset ISO_8859_4 = Charset.forName("ISO-8859-4");
253         sa.setCharset(ISO_8859_4);
254         logger.debug(logMsg);
255 
256         // wait max 8 seconds for mock server to finish. However, it should
257         // be done much sooner than that.
258         mockServer.join(8000);
259 
260         assertTrue(mockServer.isFinished());
261         assertEquals(1, mockServer.getMessageList().size());
262         String msg = new String(mockServer.getMessageList().get(0), ISO_8859_4);
263         String threadName = Thread.currentThread().getName();
264 
265         String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">";
266         assertTrue(msg.startsWith(expected));
267 
268         System.out.println(logMsg);
269         checkRegexMatch(msg, SYSLOG_PREFIX_REGEX + "\\[" + threadName + "\\] " + loggerName + " " + logMsg);
270 
271     }
272 }