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