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 java.io.IOException;
17  import java.io.OutputStream;
18  import java.net.SocketException;
19  import java.net.UnknownHostException;
20  
21  import ch.qos.logback.classic.PatternLayout;
22  import ch.qos.logback.classic.pattern.SyslogStartConverter;
23  import ch.qos.logback.classic.spi.ILoggingEvent;
24  import ch.qos.logback.classic.spi.IThrowableProxy;
25  import ch.qos.logback.classic.spi.StackTraceElementProxy;
26  import ch.qos.logback.classic.util.LevelToSyslogSeverity;
27  import ch.qos.logback.core.CoreConstants;
28  import ch.qos.logback.core.Layout;
29  import ch.qos.logback.core.net.SyslogAppenderBase;
30  import ch.qos.logback.core.net.SyslogOutputStream;
31  
32  /**
33   * This appender can be used to send messages to a remote syslog daemon.
34   * <p>
35   * For more information about this appender, please refer to the online manual
36   * at http://logback.qos.ch/manual/appenders.html#SyslogAppender
37   *
38   * @author Ceki G&uuml;lc&uuml;
39   */
40  public class SyslogAppender extends SyslogAppenderBase<ILoggingEvent> {
41  
42      static final public String DEFAULT_SUFFIX_PATTERN = "[%thread] %logger %msg";
43      static final public String DEFAULT_STACKTRACE_PATTERN = "" + CoreConstants.TAB;
44  
45      PatternLayout stackTraceLayout = new PatternLayout();
46      String stackTracePattern = DEFAULT_STACKTRACE_PATTERN;
47  
48      boolean throwableExcluded = false;
49  
50      public void start() {
51          super.start();
52          setupStackTraceLayout();
53      }
54  
55      String getPrefixPattern() {
56          return "%syslogStart{" + getFacility() + "}%nopex{}";
57      }
58  
59      @Override
60      public SyslogOutputStream createOutputStream() throws SocketException, UnknownHostException {
61          return new SyslogOutputStream(getSyslogHost(), getPort());
62      }
63  
64      /**
65       * Convert a level to equivalent syslog severity. Only levels for printing
66       * methods i.e. DEBUG, WARN, INFO and ERROR are converted.
67       *
68       * @see ch.qos.logback.core.net.SyslogAppenderBase#getSeverityForEvent(java.lang.Object)
69       */
70      @Override
71      public int getSeverityForEvent(Object eventObject) {
72          ILoggingEvent event = (ILoggingEvent) eventObject;
73          return LevelToSyslogSeverity.convert(event);
74      }
75  
76      @Override
77      protected void postProcess(Object eventObject, OutputStream sw) {
78          if (throwableExcluded)
79              return;
80  
81          ILoggingEvent event = (ILoggingEvent) eventObject;
82          IThrowableProxy tp = event.getThrowableProxy();
83  
84          if (tp == null)
85              return;
86  
87          String stackTracePrefix = stackTraceLayout.doLayout(event);
88          boolean isRootException = true;
89          while (tp != null) {
90              StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
91              try {
92                  handleThrowableFirstLine(sw, tp, stackTracePrefix, isRootException);
93                  isRootException = false;
94                  for (StackTraceElementProxy step : stepArray) {
95                      StringBuilder sb = new StringBuilder();
96                      sb.append(stackTracePrefix).append(step);
97                      sw.write(sb.toString().getBytes());
98                      sw.flush();
99                  }
100             } catch (IOException e) {
101                 break;
102             }
103             tp = tp.getCause();
104         }
105     }
106 
107     // LOGBACK-411 and LOGBACK-750
108     private void handleThrowableFirstLine(OutputStream sw, IThrowableProxy tp, String stackTracePrefix,
109             boolean isRootException) throws IOException {
110         StringBuilder sb = new StringBuilder().append(stackTracePrefix);
111 
112         if (!isRootException) {
113             sb.append(CoreConstants.CAUSED_BY);
114         }
115         sb.append(tp.getClassName()).append(": ").append(tp.getMessage());
116         sw.write(sb.toString().getBytes());
117         sw.flush();
118     }
119 
120     boolean stackTraceHeaderLine(StringBuilder sb, boolean topException) {
121 
122         return false;
123     }
124 
125     public Layout<ILoggingEvent> buildLayout() {
126         PatternLayout layout = new PatternLayout();
127         layout.getInstanceConverterMap().put("syslogStart", SyslogStartConverter.class.getName());
128         if (suffixPattern == null) {
129             suffixPattern = DEFAULT_SUFFIX_PATTERN;
130         }
131         layout.setPattern(getPrefixPattern() + suffixPattern);
132         layout.setContext(getContext());
133         layout.start();
134         return layout;
135     }
136 
137     private void setupStackTraceLayout() {
138         stackTraceLayout.getInstanceConverterMap().put("syslogStart", SyslogStartConverter.class.getName());
139 
140         stackTraceLayout.setPattern(getPrefixPattern() + stackTracePattern);
141         stackTraceLayout.setContext(getContext());
142         stackTraceLayout.start();
143     }
144 
145     public boolean isThrowableExcluded() {
146         return throwableExcluded;
147     }
148 
149     /**
150      * Setting throwableExcluded to true causes no Throwable's stack trace data to
151      * be sent to the syslog daemon. By default, stack trace data is sent to syslog
152      * daemon.
153      *
154      * @param throwableExcluded
155      * @since 1.0.4
156      */
157     public void setThrowableExcluded(boolean throwableExcluded) {
158         this.throwableExcluded = throwableExcluded;
159     }
160 
161     /**
162      * See {@link #setStackTracePattern(String).
163      *
164      * @return the stackTraceSuffixPattern
165      * @since 1.0.4
166      */
167     public String getStackTracePattern() {
168         return stackTracePattern;
169     }
170 
171     /**
172      * Stack trace lines are sent to the syslog server separately from the main
173      * message For stack trace lines, the stackTracePattern is used instead of
174      * {@link #suffixPattern}. The <b>stackTracePattern</b> option allows
175      * specification of a separate format for the non-standardized part of stack
176      * trace lines.
177      *
178      * @param stackTracePattern
179      * @since 1.0.4
180      */
181     public void setStackTracePattern(String stackTracePattern) {
182         this.stackTracePattern = stackTracePattern;
183     }
184 }