View Javadoc

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