View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, 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.core.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.core.AppenderBase;
22  import ch.qos.logback.core.CoreConstants;
23  import ch.qos.logback.core.Layout;
24  
25  /**
26   * Base class for SyslogAppender.
27   * 
28   * @author Ceki Gülcü
29   * 
30   * @param <E>
31   */
32  public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
33  
34    final static String SYSLOG_LAYOUT_URL = CoreConstants.CODES_URL
35        + "#syslog_layout";
36    final static int MSG_SIZE_LIMIT = 256 * 1024;
37  
38    Layout<E> layout;
39    String facilityStr;
40    String syslogHost;
41    protected String suffixPattern;
42    SyslogOutputStream sos;
43    int port = SyslogConstants.SYSLOG_PORT;
44  
45    public void start() {
46      int errorCount = 0;
47      if (facilityStr == null) {
48        addError("The Facility option is mandatory");
49        errorCount++;
50      }
51  
52      try {
53        sos = new SyslogOutputStream(syslogHost, port);
54      } catch (UnknownHostException e) {
55        addError("Could not create SyslogWriter", e);
56        errorCount++;
57      } catch (SocketException e) {
58        addWarn(
59            "Failed to bind to a random datagram socket. Will try to reconnect later.",
60            e);
61      }
62  
63      if (layout == null) {
64        layout = buildLayout(facilityStr);
65      }
66  
67      if (errorCount == 0) {
68        super.start();
69      }
70    }
71  
72    abstract public Layout<E> buildLayout(String facilityStr);
73  
74    abstract public int getSeverityForEvent(Object eventObject);
75  
76    @Override
77    protected void append(E eventObject) {
78      if (!isStarted()) {
79        return;
80      }
81  
82      try {
83        String msg = layout.doLayout(eventObject);
84        if(msg == null) {
85          return;
86        }
87        if (msg.length() > MSG_SIZE_LIMIT) {
88          msg = msg.substring(0, MSG_SIZE_LIMIT);
89        }
90        sos.write(msg.getBytes());
91        sos.flush();
92        postProcess(eventObject, sos);
93      } catch (IOException ioe) {
94        addError("Failed to send diagram to " + syslogHost, ioe);
95      }
96    }
97  
98    protected void postProcess(Object event, OutputStream sw) {
99  
100   }
101 
102   /**
103    * Returns the integer value corresponding to the named syslog facility.
104    * 
105    * @throws IllegalArgumentException
106    *           if the facility string is not recognized
107    */
108   static public int facilityStringToint(String facilityStr) {
109     if ("KERN".equalsIgnoreCase(facilityStr)) {
110       return SyslogConstants.LOG_KERN;
111     } else if ("USER".equalsIgnoreCase(facilityStr)) {
112       return SyslogConstants.LOG_USER;
113     } else if ("MAIL".equalsIgnoreCase(facilityStr)) {
114       return SyslogConstants.LOG_MAIL;
115     } else if ("DAEMON".equalsIgnoreCase(facilityStr)) {
116       return SyslogConstants.LOG_DAEMON;
117     } else if ("AUTH".equalsIgnoreCase(facilityStr)) {
118       return SyslogConstants.LOG_AUTH;
119     } else if ("SYSLOG".equalsIgnoreCase(facilityStr)) {
120       return SyslogConstants.LOG_SYSLOG;
121     } else if ("LPR".equalsIgnoreCase(facilityStr)) {
122       return SyslogConstants.LOG_LPR;
123     } else if ("NEWS".equalsIgnoreCase(facilityStr)) {
124       return SyslogConstants.LOG_NEWS;
125     } else if ("UUCP".equalsIgnoreCase(facilityStr)) {
126       return SyslogConstants.LOG_UUCP;
127     } else if ("CRON".equalsIgnoreCase(facilityStr)) {
128       return SyslogConstants.LOG_CRON;
129     } else if ("AUTHPRIV".equalsIgnoreCase(facilityStr)) {
130       return SyslogConstants.LOG_AUTHPRIV;
131     } else if ("FTP".equalsIgnoreCase(facilityStr)) {
132       return SyslogConstants.LOG_FTP;
133     } else if ("LOCAL0".equalsIgnoreCase(facilityStr)) {
134       return SyslogConstants.LOG_LOCAL0;
135     } else if ("LOCAL1".equalsIgnoreCase(facilityStr)) {
136       return SyslogConstants.LOG_LOCAL1;
137     } else if ("LOCAL2".equalsIgnoreCase(facilityStr)) {
138       return SyslogConstants.LOG_LOCAL2;
139     } else if ("LOCAL3".equalsIgnoreCase(facilityStr)) {
140       return SyslogConstants.LOG_LOCAL3;
141     } else if ("LOCAL4".equalsIgnoreCase(facilityStr)) {
142       return SyslogConstants.LOG_LOCAL4;
143     } else if ("LOCAL5".equalsIgnoreCase(facilityStr)) {
144       return SyslogConstants.LOG_LOCAL5;
145     } else if ("LOCAL6".equalsIgnoreCase(facilityStr)) {
146       return SyslogConstants.LOG_LOCAL6;
147     } else if ("LOCAL7".equalsIgnoreCase(facilityStr)) {
148       return SyslogConstants.LOG_LOCAL7;
149     } else {
150       throw new IllegalArgumentException(facilityStr
151           + " is not a valid syslog facility string");
152     }
153   }
154 
155   /**
156    * Returns the value of the <b>SyslogHost</b> option.
157    */
158   public String getSyslogHost() {
159     return syslogHost;
160   }
161 
162   /**
163    * The <b>SyslogHost</b> option is the name of the the syslog host where log
164    * output should go.
165    * 
166    * <b>WARNING</b> If the SyslogHost is not set, then this appender will fail.
167    */
168   public void setSyslogHost(String syslogHost) {
169     this.syslogHost = syslogHost;
170   }
171 
172   /**
173    * Returns the string value of the <b>Facility</b> option.
174    * 
175    * See {@link #setFacility} for the set of allowed values.
176    */
177   public String getFacility() {
178     return facilityStr;
179   }
180 
181   /**
182    * The <b>Facility</b> option must be set one of the strings KERN, USER, MAIL,
183    * DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT,
184    * ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6,
185    * LOCAL7. Case is not important.
186    * 
187    * <p>
188    * See {@link SyslogConstants} and RFC 3164 for more information about the
189    * <b>Facility</b> option.
190    */
191   public void setFacility(String facilityStr) {
192     if (facilityStr != null) {
193       facilityStr = facilityStr.trim();
194     }
195     this.facilityStr = facilityStr;
196   }
197 
198   /**
199    * 
200    * @return
201    */
202   public int getPort() {
203     return port;
204   }
205 
206   /**
207    * The port number on the syslog server to connect to. Normally, you would not
208    * want to change the default value, that is 514.
209    */
210   public void setPort(int port) {
211     this.port = port;
212   }
213 
214   public Layout<E> getLayout() {
215     return layout;
216   }
217 
218   public void setLayout(Layout<E> layout) {
219     addWarn("The layout of a SyslogAppender cannot be set directly. See also "
220         + SYSLOG_LAYOUT_URL);
221   }
222 
223   @Override
224   public void stop() {
225     sos.close();
226     super.stop();
227   }
228 
229 /**
230    * See {@link #setSuffixPattern(String).
231    * 
232    * @return
233    */
234   public String getSuffixPattern() {
235     return suffixPattern;
236   }
237 
238   /**
239    * The <b>suffixPattern</b> option specifies the format of the
240    * non-standardized part of the message sent to the syslog server.
241    * 
242    * @param suffixPattern
243    */
244   public void setSuffixPattern(String suffixPattern) {
245     this.suffixPattern = suffixPattern;
246   }
247 }