KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > protomatter > syslog > SyslogHandler


1 package com.protomatter.syslog;
2
3 /**
4  * {{{ The Protomatter Software License, Version 1.0
5  * derived from The Apache Software License, Version 1.1
6  *
7  * Copyright (c) 1998-2002 Nate Sammons. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed for the
24  * Protomatter Software Project
25  * (http://protomatter.sourceforge.net/)."
26  * Alternately, this acknowledgment may appear in the software itself,
27  * if and wherever such third-party acknowledgments normally appear.
28  *
29  * 4. The names "Protomatter" and "Protomatter Software Project" must
30  * not be used to endorse or promote products derived from this
31  * software without prior written permission. For written
32  * permission, please contact support@protomatter.com.
33  *
34  * 5. Products derived from this software may not be called "Protomatter",
35  * nor may "Protomatter" appear in their name, without prior written
36  * permission of the Protomatter Software Project
37  * (support@protomatter.com).
38  *
39  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
40  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42  * DISCLAIMED. IN NO EVENT SHALL THE PROTOMATTER SOFTWARE PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
46  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
49  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE. }}}
51  */

52
53 import java.net.InetAddress JavaDoc;
54 import java.util.*;
55 import java.util.logging.*;
56 import java.io.File JavaDoc;
57 import java.text.MessageFormat JavaDoc;
58 import com.protomatter.syslog.xml.SyslogXML;
59 import com.protomatter.syslog.SyslogInitException;
60 import com.protomatter.util.ChainedRuntimeException;
61 import com.protomatter.util.StackTraceUtil;
62
63 /**
64  * A JDK 1.4 logging system handler to route messages
65  * into Syslog. Logger names are converted to
66  * syslog channel names.<P>
67  *
68  * The following log properties file assigns
69  * the <TT>SyslogHandler</TT> class as the only
70  * log handler.<P>
71  *
72  * <UL><TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
73  * <TR><TD>
74  * <PRE><B><FONT size="-1">
75  *
76  * .level = ALL
77  *
78  * handlers = com.protomatter.syslog.SyslogHandler
79  *
80  * </FONT></B></PRE>
81  * </TD></TR></TABLE></UL><P>
82  *
83  * Here's a usage example:<P>
84  *
85  * <UL><TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
86  * <TR><TD>
87  * <PRE><B><FONT size="-1">
88  * import java.util.logging.Logger;
89  *
90  * ...
91  *
92  * // Make a new logger
93  * Logger myLogger = Logger.getLogger("foo.bar");
94  *
95  * // Write some log messages
96  * myLogger.info("Info message to my logger");
97  * myLogger.warning("Warning message to my logger");
98  * myLogger.severe("Severe message to my logger");
99  *
100  * </FONT></B></PRE>
101  * </TD></TR></TABLE></UL><P>
102  *
103  * If you have syslog configured to show the channel name and
104  * log all message levels, you'll see something like this:<P>
105  *
106  * <UL><TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
107  * <TR><TD>
108  * <PRE><B><FONT size="-1">
109  * 11/01/2001 20:09:16 [INFO] [foo.bar ] Test.main():23 Info message to my logger
110  * 11/01/2001 20:09:16 [WARN] [foo.bar ] Test.main():25 Warning message to my logger
111  * 11/01/2001 20:09:16 [EROR] [foo.bar ] Test.main():27 Severe message to my logger
112  * </FONT></B></PRE>
113  * </TD></TR></TABLE></UL><P>
114  *
115  * If the "<TT>SyslogHandler.xml</TT>" system property is set,
116  * this class will call <TT>SyslogXML.configure()</TT> with
117  * that configuration file.<P>
118  *
119  * So, to configure syslog and use the JDK 1.4 logging API to
120  * write to it, do the following:
121  *
122  * <UL><TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
123  * <TR><TD>
124  * <PRE><B><FONT size="-1">
125  *
126  * java \
127  * ...
128  * -DSyslogHandler.xml=/path/to/syslog.xml \
129  * -Djava.util.logging.config.file=/path/to/logging.properties \
130  * ...
131  * java-main-class
132  *
133  * </FONT></B></PRE>
134  * </TD></TR></TABLE></UL><P>
135  *
136  * Note that if you use this class, and don't have Syslog configured to compute
137  * the caller class and method, then the caller name in your logs will be
138  * incorrect. This is because the JDK 1.4 logging API doesn't have a mechanism
139  * for directly getting a reference to the caller.<P>
140  */

141 public class SyslogHandler
142 extends Handler
143 {
144   private boolean open = true;
145   private Map levelMap = null;
146
147   private static String JavaDoc CONFIG_FILE_PROPERTY = "SyslogHandler.xml";
148
149   static
150   {
151     String JavaDoc xmlFile = System.getProperty(CONFIG_FILE_PROPERTY);
152     if (xmlFile != null)
153     {
154       try
155       {
156         SyslogXML.configure(new File JavaDoc(xmlFile));
157       }
158       catch (SyslogInitException x)
159       {
160         throw new ChainedRuntimeException(Syslog.getResourceString(MessageConstants.CANNOT_CONFIGURE_MESSAGE), x);
161       }
162     }
163   }
164
165   /**
166    * Create a new handler for routing messages to Syslog.
167    */

168   public SyslogHandler()
169   {
170     super();
171
172     resetLevelMap();
173   }
174
175   /**
176    * Reset the level conversion map to the default.
177    * The default map is:<P>
178    *
179    * <table border=1 cellpadding=4 cellspacing=0>
180    * <tr>
181    * <th>java.util.logging.Level</th>
182    * <th>Syslog Level</th>
183    * </tr>
184    * <tr>
185    * <td><TT>Level.SEVERE</TT></td>
186    * <td><TT>Syslog.ERROR</TT></td>
187    * </tr>
188    * <tr>
189    * <td><TT>Level.WARNING</TT></td>
190    * <td><TT>Syslog.WARNING</TT></td>
191    * </tr>
192    * <tr>
193    * <td><TT>Level.INFO</TT></td>
194    * <td><TT>Syslog.INFO</TT></td>
195    * </tr>
196    * <tr>
197    * <td><TT>Level.CONFIG</TT></td>
198    * <td><TT>Syslog.DEBUG</TT></td>
199    * </tr>
200    * <tr>
201    * <td><TT>Level.FINE</TT></td>
202    * <td><TT>Syslog.DEBUG</TT></td>
203    * </tr>
204    * <tr>
205    * <td><TT>Level.FINER</TT></td>
206    * <td><TT>Syslog.DEBUG</TT></td>
207    * </tr>
208    * <tr>
209    * <td><TT>Level.FINEST</TT></td>
210    * <td><TT>Syslog.DEBUG</TT></td>
211    * </tr>
212    * </table>
213    */

214   public void resetLevelMap()
215   {
216     Map levelMap = new HashMap();
217     levelMap.put(Level.SEVERE, new Integer JavaDoc(Syslog.ERROR));
218     levelMap.put(Level.WARNING, new Integer JavaDoc(Syslog.WARNING));
219     levelMap.put(Level.INFO, new Integer JavaDoc(Syslog.INFO));
220     levelMap.put(Level.CONFIG, new Integer JavaDoc(Syslog.DEBUG));
221     levelMap.put(Level.FINE, new Integer JavaDoc(Syslog.DEBUG));
222     levelMap.put(Level.FINER, new Integer JavaDoc(Syslog.DEBUG));
223     levelMap.put(Level.FINEST, new Integer JavaDoc(Syslog.DEBUG));
224     setLevelMap(levelMap);
225   }
226
227   /**
228    * Close the handler.
229    */

230   public void close()
231   {
232     open = false;
233   }
234
235   /**
236    * Flush this handler. This method simply
237    * calls <TT>Syslog.flush()</TT>.
238    *
239    * @see Syslog#flush()
240    */

241   public void flush()
242   {
243     Syslog.flush();
244   }
245
246   /**
247    * Route the given log record into Syslog.
248    *
249    * If this handler has been closed, the record is ignored.
250    * If a filter has been set, then it is applied to record
251    * to see if it should be passed on to Syslog.<P>
252    *
253    * The formatter is ignored. Arguments passed as
254    * message parameters are parsed and replaced
255    * in the message using the <tt>java.text.MessageFormat</tt>
256    * class.<P>
257    *
258    * If a throwable has been set, it is used as the message
259    * detail when the record is sent to Syslog.<P>
260    *
261    * The log level is converted from a <TT>java.util.logging.Level</TT>
262    * according to the level map for this handler.<P>
263    *
264    * The name of the <TT>java.util.logging.Logger</TT> is used
265    * as the channel name.<P>
266    *
267    * Once these conversions have been made, the information is
268    * passed onto Syslog for further processing.
269    */

270   public void publish(java.util.logging.LogRecord JavaDoc record)
271   {
272     if (!open)
273       return;
274
275     // check with a filter if there is one.
276
Filter filter = getFilter();
277     if (filter != null && !filter.isLoggable(record))
278       return;
279
280     // format the message
281
String JavaDoc message = record.getMessage();
282     Object JavaDoc params[] = record.getParameters();
283     if (params != null && (params.length > 0))
284     {
285       message = MessageFormat.format(message, params);
286     }
287
288     // convert JDK 1.4 level to Syslog level
289
int syslogLevel = getSyslogLevel(record.getLevel());
290
291     // get the local thread and its name
292
Thread JavaDoc currentThread = Thread.currentThread();
293     String JavaDoc threadName = currentThread.getName();
294
295     // get message send time
296
long messageTime = record.getMillis();
297
298     // get initiating class name
299
Object JavaDoc loggerClass = record.getSourceClassName();
300     if (loggerClass == null)
301       loggerClass = this;
302
303     // get the detail. This is the exception being logged, if any
304
Object JavaDoc detail = record.getThrown();
305
306     // treat the logger name as the channel.
307
String JavaDoc channel = record.getLoggerName();
308
309     // determine call stack depth. The
310
// entering() and exiting() methods are
311
// one layer deeper. This is so we can
312
// accurately determine class, method
313
// and line number at runtime.
314
int depth = 4;
315     if ("java.util.logging.Logger".equals(StackTraceUtil.whereAmI(depth).className))
316         depth++;
317
318     // send the message off to Syslog.
319
Syslog.log(
320         Syslog.getLocalHostName(),
321         loggerClass,
322         channel,
323         message,
324         detail,
325         syslogLevel,
326         currentThread,
327         threadName,
328         messageTime,
329         depth
330         );
331   }
332
333   /**
334    * Convert a JDK 1.4 log level to a Syslog level.
335    */

336   private final int getSyslogLevel(java.util.logging.Level JavaDoc level)
337   {
338     return ((Integer JavaDoc)this.levelMap.get(level)).intValue();
339   }
340
341   /**
342    * Get the conversion map for levels. The key in the
343    * map is an instance of <TT>java.util.logging.Level</TT>
344    * and the value is a <TT>java.lang.Integer</TT> which is
345    * a wrapper for <TT>Syslog.DEBUG</TT>, <TT>Syslog.INFO</TT>, etc.
346    */

347   public Map getLevelMap()
348   {
349     return this.levelMap;
350   }
351
352   /**
353    * Set the conversion map for levels. The key in the
354    * map is an instance of <TT>java.util.logging.Level</TT>
355    * and the value is a <TT>java.lang.Integer</TT> which is
356    * a wrapper for <TT>Syslog.DEBUG</TT>, <TT>Syslog.INFO</TT>, etc.
357    */

358   public void setLevelMap(Map levelMap)
359   {
360     this.levelMap = levelMap;
361   }
362 }
363
Popular Tags