KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log4j > net > DatagramStringAppender


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.log4j.net;
18
19 import java.net.DatagramSocket JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.DatagramPacket JavaDoc;
22 import java.net.UnknownHostException JavaDoc;
23 import java.net.SocketException JavaDoc;
24
25 import org.apache.log4j.helpers.OptionConverter;
26 import org.apache.log4j.AppenderSkeleton;
27 import org.apache.log4j.spi.LoggingEvent;
28 import org.apache.log4j.Category;
29 import org.apache.log4j.Priority;
30 import org.apache.log4j.Layout;
31
32 import org.apache.log4j.helpers.SingleLineTracerPrintWriter;
33 import org.apache.log4j.helpers.LogLog;
34 import org.apache.log4j.helpers.QuietWriter;
35
36
37 /**
38     Use DatagramStringAppender to send log messages to a remote daemon
39     which accepts Datagram (UDP) messages.
40     <p>
41     The benefits of UDP are that the client is guarunteed not to
42     slow down if the network or remote log daemon is slow, and that
43     no permanent TCP connection between client and server exists.
44     <p>
45     The disadvantages are that log messages can be lost if the network
46     or remote daemon are under excessive load.
47     <p>
48     This class builts the final message string <b>before</b> sending
49     the UDP packet, hence the "string" component in the class name. This
50     means that the receiving application can be written in any language.
51     The data is transmitted in whatever encoding is specified in the
52     configuration file; this may be an 8-bit encoding (eg ISO-8859-1, also
53     known as LATIN-1) or a larger encoding, eg UTF-16.
54     <p>
55     An alternative to building the message string within DatagramStringAppender
56     would be to serialize & send the complete logging event object (perhaps
57     such a class could be called a DatagramSerialAppender??). The
58     receiving end could then be configured with appropriate Layout objects
59     to generate the actual logged messages. This would ensure that the
60     logging of messages from different sources is done in a consistent
61     format, and give a central place to configure that format. It would ensure
62     (by transmitting messages as unicode) that the receiving end could control
63     the encoding in which the output is generated. It also would possibly allow
64     he receiving end to use the full log4j flexibility to pass the event to
65     different appenders at the receiving end, as the category information is
66     retained, etc. However, this does require that the receiving end is in
67     java, and that all clients of the logging daemon are java applications.
68     In contrast, this DatagramStringAppender can send mesages to a log daemon
69     that accepts messages from a variety of sources.
70
71     @author Simon Kitching
72  */

73 public class DatagramStringAppender extends AppenderSkeleton {
74
75    /**
76      A string constant used in naming the option for setting the destination
77      server for messages. Current value of this string constant is
78      <b>DatagramHost</b>. */

79   public static final String JavaDoc DATAGRAM_HOST_OPTION = "DatagramHost";
80
81    /**
82      A string constant used in naming the option for setting the destination
83      port for messages. Current value of this string constant is
84      <b>DatagramPort</b>. */

85   public static final String JavaDoc DATAGRAM_PORT_OPTION = "DatagramPort";
86
87    /**
88      A string constant used in naming the option for setting the character
89      encoding used when generating the log message. Current value of this
90      string constant is <b>DatagramEncoding</b>. */

91   public static final String JavaDoc DATAGRAM_ENCODING_OPTION = "DatagramEncoding";
92
93    /**
94      The default value for the "host" attribute, ie the machine to which
95      messages are sent. Current value of this string constant is
96      <b>localhost</b>. */

97   public static final String JavaDoc DEFAULT_HOST = "localhost";
98
99    /**
100      The default value for the "port" attribute, ie the UDP port to which
101      messages are sent. Current value of this integer constant is
102      <b>8200</b>. This value was chosen for no particular reason. */

103   public static final int DEFAULT_PORT = 8200;
104
105    /**
106      The default value for the "encoding" attribute, ie the way in which
107      unicode message strings are converted into a stream of bytes before
108      their transmission as a UDP packet. The current value of this constant
109      is <b>null</b>, which means that the default platform encoding will
110      be used. */

111   public static final String JavaDoc DEFAULT_ENCODING = null;
112
113   String JavaDoc host = DEFAULT_HOST;
114   int port = DEFAULT_PORT;
115   String JavaDoc encoding = DEFAULT_ENCODING;
116
117   SingleLineTracerPrintWriter stp;
118   QuietWriter qw;
119
120   public
121   DatagramStringAppender() {
122     this.setDestination(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_ENCODING);
123   }
124
125   public
126   DatagramStringAppender(Layout layout) {
127     this.setLayout(layout);
128     this.setDestination(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_ENCODING);
129   }
130
131   public
132   DatagramStringAppender(Layout layout, String JavaDoc host, int port) {
133     this.setLayout(layout);
134     this.setDestination(host, port, DEFAULT_ENCODING);
135   }
136
137   public
138   DatagramStringAppender(Layout layout, String JavaDoc host, int port, String JavaDoc encoding) {
139     this.setLayout(layout);
140     this.setDestination(host, port, encoding);
141   }
142
143   /**
144      Release any resources held by this Appender
145    */

146   public
147   void close() {
148     closed = true;
149     // A DatagramWriter is UDP based and needs no opening. Hence, it
150
// can't be closed. We just unset the variables here.
151
qw = null;
152     stp = null;
153   }
154
155   public
156   void append(LoggingEvent event) {
157     if(!isAsSevereAsThreshold(event.priority))
158       return;
159
160     // We must not attempt to append if qw is null.
161
if(qw == null) {
162       errorHandler.error(
163         "No host is set for DatagramStringAppender named \""
164         + this.name + "\".");
165       return;
166     }
167
168     String JavaDoc buffer = layout.format(event);
169     qw.write(buffer);
170
171     if(event.throwable != null)
172       event.throwable.printStackTrace(stp);
173     else if (event.throwableInformation != null) {
174       // we must be the receiver of a serialized/deserialized LoggingEvent;
175
// the event's throwable member is transient, ie becomes null when
176
// deserialized, but that's ok because throwableInformation should
177
// have the string equivalent of the same info (ie stack trace)
178
qw.write(event.throwableInformation);
179     }
180   }
181
182   /**
183      Activate the options set via the setOption method.
184
185      @see #setOption
186   */

187   public
188   void activateOptions() {
189     this.setDestination(this.host, this.port, this.encoding);
190   }
191
192   /**
193      Returns the option names for this component, namely the string
194      array consisting of {{@link #DATAGRAM_HOST_OPTION}, {@link
195      #DATAGRAM_PORT_OPTION}, {@link #DATAGRAM_ENCODING_OPTION} */

196   public
197   String JavaDoc[] getOptionStrings() {
198     return OptionConverter.concatanateArrays(super.getOptionStrings(),
199               new String JavaDoc[] {
200             DATAGRAM_HOST_OPTION,
201             DATAGRAM_PORT_OPTION,
202             DATAGRAM_ENCODING_OPTION});
203   }
204
205   /**
206      The DatagramStringAppender requires a layout. Hence, this method return
207      <code>true</code>.
208
209      @since 0.8.4 */

210   public
211   boolean requiresLayout() {
212     return true;
213   }
214
215   /**
216     Set DatagramStringAppender specific parameters.
217     <p>
218     The recognized options are <b>DatagramHost</b>, <b>DatagramPort</b> and
219     <b>DatagramEncoding</b>, i.e. the values of the string constants
220     {@link #DATAGRAM_HOST_OPTION}, {@link #DATAGRAM_PORT_OPTION} and
221     {@link #DATAGRAM_ENCODING_OPTION} respectively.
222     <p>
223     <dl>
224     <p>
225     <dt><b>DatagramHost</b>
226     <dd>
227     The name (or ip address) of the host machine where log output should go.
228     If the DatagramHost is not set, then this appender will default to
229     {@link #DEFAULT_HOST}.
230     <p>
231     <dt><b>DatagramPort</b>
232     <dd>
233     The UDP port number where log output should go. See {@link #DEFAULT_PORT}
234     <p>
235     <dt><b>DatagramEncoding</b>
236     <dd>
237     The ISO character encoding to be used when converting the Unicode
238     message to a sequence of bytes within a UDP packet. If not defined, then
239     the encoding defaults to the default platform encoding.
240     </dl>
241     */

242   public
243   void setOption(String JavaDoc option, String JavaDoc value) {
244     if(value == null) return;
245
246     super.setOption(option, value);
247
248     if(option.equals(DATAGRAM_HOST_OPTION))
249     {
250       this.host = value;
251     }
252     else if(option.equals(DATAGRAM_PORT_OPTION))
253     {
254       this.port = OptionConverter.toInt(value, DEFAULT_PORT);
255     }
256     else if(option.equals(DATAGRAM_ENCODING_OPTION))
257     {
258       this.encoding = value;
259     }
260   }
261
262   public
263   void setDestination(String JavaDoc host, int port, String JavaDoc encoding) {
264     if (host==null) {
265       LogLog.error("setDestination: host is null");
266       host = DEFAULT_HOST;
267     }
268     
269     this.host = host;
270     this.port = port;
271     this.encoding = encoding;
272
273     this.qw = new QuietWriter(
274         new DatagramStringWriter(host, port, encoding),
275         errorHandler);
276     this.stp = new SingleLineTracerPrintWriter(qw);
277   }
278
279   public
280   void setLayout(Layout layout) {
281     this.layout = layout;
282   }
283 }
284
Popular Tags