KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.PrintWriter JavaDoc;
54 import java.util.*;
55 import java.text.*;
56 import java.net.*;
57 import java.io.*;
58 import java.lang.reflect.*;
59
60 import com.protomatter.util.*;
61
62 /**
63  * A simple log entry formatter. This class is used by several of
64  * the included <tt>Syslogger</tt> implementations to format their
65  * log entries.
66  *
67  * @see com.protomatter.syslog.xml.SimpleSyslogTextFormatter_Helper XML configuration class
68  */

69 public class SimpleSyslogTextFormatter
70 implements SyslogTextFormatter
71 {
72   private static String JavaDoc crString = System.getProperty("line.separator");
73   private static char[] cr = System.getProperty("line.separator").toCharArray();
74   private static char[] rb = " [".toCharArray();
75   private static char[] lb = "] ".toCharArray();
76   private static char rb_ns = '[';
77   private static char[] sp = " ".toCharArray();
78   private static char[] parens = "()".toCharArray();
79   private static char sp_1 = ' ';
80   private static char dot = '.';
81   private static char colon = ':';
82
83   private static char[] DEBUG = "DBUG".toCharArray();
84   private static char[] INFO = "INFO".toCharArray();
85   private static char[] WARNING = "WARN".toCharArray();
86   private static char[] ERROR = "EROR".toCharArray();
87   private static char[] FATAL = "FTAL".toCharArray();
88   private static char[] UNKNOWN_LEVEL = "????".toCharArray();
89
90   private static String JavaDoc CH_ALL_CHANNEL = "ALL_CHANNEL";
91   private static String JavaDoc CH_DEF_CHANNEL = "DEFAULT_CHANNEL";
92
93   private DateFormat dateFormat = null;
94   private TimeZone dateFormatTimeZone = TimeZone.getDefault();
95   private String JavaDoc dateFormatString = null;
96   private long lastDate = -1;
97   private char[] lastDateString = null;
98   private int dateFormatCacheTime = 1000;
99   private boolean showCaller = true;
100   private boolean showChannel = false;
101   private boolean showThreadName = false;
102   private boolean showHostName = false;
103
104   private int classWidth = 20;
105   private int hostWidth = 15;
106   private int channelWidth = 15;
107   private int threadWidth = 15;
108
109   /**
110    * Default constructor.
111    */

112   public SimpleSyslogTextFormatter()
113   {
114     super();
115     setDateFormat("MM/dd/yyyy HH:mm:ss");
116   }
117
118   /**
119    * Format the given log entry.
120    */

121   public void formatLogEntry(StringBuffer JavaDoc b, SyslogMessage message)
122   {
123     synchronized (b)
124     {
125       b.append(formatDate(message.time));
126       b.append(rb);
127       b.append(getStringForLevel(message.level));
128       b.append(lb);
129
130       if (showChannel)
131       {
132         if (message.channel.equals(Syslog.ALL_CHANNEL))
133         {
134           b.append(rb_ns);
135           justify(b, CH_ALL_CHANNEL, getChannelWidth());
136           b.append(lb);
137         }
138         else if (message.channel.equals(Syslog.DEFAULT_CHANNEL))
139         {
140           b.append(rb_ns);
141           justify(b, CH_DEF_CHANNEL, getChannelWidth());
142           b.append(lb);
143         }
144         else
145         {
146           b.append(rb_ns);
147           justify(b, message.channel, getChannelWidth());
148           b.append(lb);
149         }
150       }
151
152       if (showHostName)
153       {
154         justify(b, getHostname(message.host), getHostWidth());
155         b.append(sp_1);
156       }
157
158       if (showThreadName)
159       {
160         b.append(rb_ns);
161         b.append("T:");
162         justify(b, message.threadName, getThreadWidth());
163         b.append(lb);
164       }
165       if (showCaller)
166       {
167         formatLoggerClassName(b, message);
168       }
169
170       if (message.msg != null)
171       {
172         b.append(sp);
173         b.append(message.msg);
174       }
175       b.append(cr);
176       if (message.detail != null)
177       {
178         formatMessageDetail(b, message);
179       }
180     }
181   }
182
183   public void formatLoggerClassName(StringBuffer JavaDoc b, SyslogMessage message)
184   {
185     trimFromLastPeriod(b, message.loggerClassname, message.callingMethodName,
186         message.callingMethodLineNumber, getClassWidth());
187   }
188
189   public void formatMessageDetail(StringBuffer JavaDoc b, SyslogMessage message)
190   {
191     if (message.detail == null)
192       return;
193
194     String JavaDoc temp = null;
195
196     // include stack traces in the output if it's a Throwable
197
if (message.detail instanceof Throwable JavaDoc)
198     {
199       ByteArrayOutputStream bs = new ByteArrayOutputStream();
200       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(bs);
201       Throwable JavaDoc e = (Throwable JavaDoc)message.detail;
202       Throwable JavaDoc e2 = e;
203       Object JavaDoc[] junk = null;
204       String JavaDoc methodCalled = null;
205       while (e2 != null)
206       {
207         if (methodCalled != null)
208         {
209           pw.print(methodCalled);
210           pw.print("(): ");
211         }
212         e2.printStackTrace(pw);
213         junk = getNextException(e2);
214         e2 = (Throwable JavaDoc)junk[1];
215         methodCalled = (String JavaDoc)junk[0];
216       }
217       pw.flush();
218       temp = bs.toString();
219       b.append(temp);
220       if (!temp.endsWith(crString))
221         b.append(cr);
222     }
223     else
224     {
225       temp = message.detail.toString();
226       b.append(temp);
227       if (!temp.endsWith(crString))
228         b.append(cr);
229     }
230   }
231
232   /**
233    * Get the "next" exception in this series. This method
234    * will look for a no-arg method on the given object that
235    * returns a subclass of throwable. It will skip the
236    * "fillInStackTrace" method. The return type is
237    * a two-element object array. The first element is
238    * the method name (or null) that was called to get
239    * the next exception, and the second element is the
240    * instance of the Throwable.
241    */

242   protected Object JavaDoc[] getNextException(Throwable JavaDoc t)
243   {
244     if (t == null)
245       return null;
246     Method methods[] = t.getClass().getMethods();
247     Class JavaDoc pt[] = null;
248     Class JavaDoc rt = null;
249     boolean isFIST = false;
250     String JavaDoc name = null;
251     Object JavaDoc junk[] = new Object JavaDoc[2];
252
253     for (int i=0; i<methods.length; i++)
254     {
255       rt = methods[i].getReturnType();
256       pt = methods[i].getParameterTypes();
257       name = methods[i].getName();
258       isFIST = name.equals("fillInStackTrace"); // skip this guy
259
if (!isFIST && pt.length == 0 && Throwable JavaDoc.class.isAssignableFrom(rt))
260       {
261         try
262         {
263           junk[0] = name;
264           junk[1] = (Throwable JavaDoc)methods[i].invoke(t, new Object JavaDoc[0]);
265           return junk;
266         }
267         catch (Throwable JavaDoc x)
268         {
269           // OK, give up.
270
return junk;
271         }
272       }
273     }
274     return junk;
275   }
276
277   protected char[] getStringForLevel(int level)
278   {
279     switch (level)
280     {
281       case Syslog.DEBUG: return DEBUG;
282       case Syslog.INFO: return INFO;
283       case Syslog.WARNING: return WARNING;
284       case Syslog.ERROR: return ERROR;
285       case Syslog.FATAL: return FATAL;
286       default: return UNKNOWN_LEVEL;
287     }
288   }
289
290   public String JavaDoc getHostname(InetAddress host)
291   {
292     if (host == null)
293       return "<null>";
294
295     String JavaDoc ip = host.getHostAddress();
296     String JavaDoc name = host.getHostName();
297     if (ip.equals(name))
298       return ip;
299
300     int idx = name.indexOf(".");
301     if (idx == -1)
302       return name;
303     return name.substring(0, idx);
304   }
305
306   /**
307    * Set the format for logging dates.
308    */

309   public void setDateFormat(String JavaDoc format)
310   {
311     this.dateFormatString = format;
312     this.dateFormat = new SimpleDateFormat(format);
313     setDateFormatTimezone(TimeZone.getDefault());
314     resetDateFormat();
315   }
316
317   /**
318    * Get the format for logging dates.
319    */

320   public String JavaDoc getDateFormat()
321   {
322     return this.dateFormatString;
323   }
324
325   /**
326    * Set wether we should show the host name in the output.
327    * If this is set to <tt>true</tt> and the hostname
328    * has not been set on Syslog yet, the <tt>Syslog.setLocalHostName()</tt>
329    * method is called.
330    */

331   public void setShowHostName(boolean showHostName)
332   {
333     this.showHostName = showHostName;
334     if (showHostName && (Syslog.getLocalHostName() == null))
335     {
336       Syslog.setLocalHostName();
337     }
338   }
339
340   /**
341    * Get wether we should show the host name in the output.
342    */

343   public boolean getShowHostName()
344   {
345     return this.showHostName;
346   }
347
348   /**
349    * Set wether we should show the thread name in the output.
350    */

351   public void setShowThreadName(boolean showThreadName)
352   {
353     this.showThreadName = showThreadName;
354   }
355
356   /**
357    * Get wether we should show the thread name in the output.
358    */

359   public boolean getShowThreadName()
360   {
361     return this.showThreadName;
362   }
363
364   /**
365    * Set wether we should show the caller name in the output.
366    */

367   public void setShowCaller(boolean showCaller)
368   {
369     this.showCaller = showCaller;
370   }
371
372   /**
373    * Get wether we should show the caller name in the output.
374    */

375   public boolean getShowCaller()
376   {
377     return this.showCaller;
378   }
379
380   /**
381    * Set wether we should show the channel name in the output.
382    */

383   public void setShowChannel(boolean showChannel)
384   {
385     this.showChannel = showChannel;
386   }
387
388   /**
389    * Get wether we should show the channel name in the output.
390    */

391   public boolean getShowChannel()
392   {
393     return this.showChannel;
394   }
395
396   /**
397    * Set the number of milliseconds a date format should
398    * be cached. This is also the resolution of the timestamp
399    * in log entries. Default is 1000ms (1 second).
400    */

401   public void setDateFormatCacheTime(int cacheTime)
402   {
403     this.dateFormatCacheTime = cacheTime;
404   }
405
406   /**
407    * Get the number of milliseconds a date format should
408    * be cached. This is also the resolution of the timestamp
409    * in log entries. Default is 1000ms (1 second).
410    */

411   public int getDateFormatCacheTime()
412   {
413     return this.dateFormatCacheTime;
414   }
415
416   /**
417    * Set the timezone of the date format. Default
418    * is <tt>TimeZone.getDefault()</tt>.
419    */

420   public void setDateFormatTimezone(TimeZone zone)
421   {
422     this.dateFormatTimeZone = zone;
423     this.dateFormat.setTimeZone(zone);
424   }
425
426   /**
427    * Get the timezone of the date format.
428    */

429   public TimeZone getDateFormatTimezone()
430   {
431     return this.dateFormatTimeZone;
432   }
433
434   /**
435    * Format the given date with the dateformat that's been set.
436    * This will cache the date until it's been long enough
437    * for the date format cache time to have expired.
438    *
439    * @see #setDateFormatCacheTime
440    */

441   protected char[] formatDate(long theDate)
442   {
443     // do the check outside a synchronized block so we
444
// don't sync unless absolutely necessary.
445
if (lastDate == -1 || theDate > lastDate+dateFormatCacheTime)
446     {
447       synchronized (dateFormat)
448       {
449         // check again now that we're synchronized.
450
if (lastDate == -1 || theDate > lastDate+dateFormatCacheTime)
451         {
452           lastDateString = dateFormat.format(new Date(theDate)).toCharArray();
453           lastDate = theDate;
454         }
455       }
456     }
457     return lastDateString;
458   }
459
460   /**
461    * Given something like "foo.bar.Baz" this will return "Baz".
462    */

463   protected void trimFromLastPeriod(StringBuffer JavaDoc b, String JavaDoc s, int width)
464   {
465     trimFromLastPeriod(b, s, null, StackTraceInfo.LINE_NUMBER_UNKNOWN, width);
466   }
467
468   /**
469    * Given something like "foo.bar.Baz" this will return "Baz".
470    */

471   protected void trimFromLastPeriod(StringBuffer JavaDoc b, String JavaDoc className, String JavaDoc method, int line, int width)
472   {
473     char data[] = (className == null) ? new char[0] : className.toCharArray();
474
475     int i=data.length;
476     for (; --i>=0 && data[i] != '.';);
477
478     i++;
479     int len = data.length - i;
480     b.append(data, i, len);
481     len = width - len;
482
483     if (method != null)
484     {
485       b.append(dot);
486       b.append(method);
487       b.append(parens);
488       len -= 3; // dot + parens
489
len -= method.length();
490       if (line != StackTraceInfo.LINE_NUMBER_UNKNOWN)
491       {
492         b.append(colon);
493         String JavaDoc lineString = String.valueOf(line);
494         b.append(lineString);
495         len--;
496         len -= lineString.length();
497       }
498     }
499
500     for (;--len>=0;)
501       b.append(sp_1);
502   }
503
504   /**
505    * Trim a string after the last "." (dot).
506    */

507   protected String JavaDoc trimFromLastPeriod(String JavaDoc s)
508   {
509     int pos = s.lastIndexOf('.');
510     if (pos >= 0)
511       return s.substring(pos+1);
512     else
513       return s;
514   }
515
516   /**
517    * Reset the <tt>formatDate(...)</tt> method so that it's
518    * guaranteed to not return a cached date string the
519    * next time it's called.
520    */

521   public void resetDateFormat()
522   {
523     this.lastDate = -1;
524   }
525
526   /**
527    * Get the log header. This simply returns an empty string.
528    */

529   public String JavaDoc getLogHeader()
530   {
531     return "";
532   }
533
534   /**
535    * Get the log footer. This simply returns an empty string.
536    */

537   public String JavaDoc getLogFooter()
538   {
539     return "";
540   }
541
542   /**
543    * Get the width of the caller class name field.
544    */

545   public int getClassWidth()
546   {
547     return this.classWidth;
548   }
549
550   /**
551    * Set the width of the caller class name field.
552    */

553   public void setClassWidth(int classWidth)
554   {
555     this.classWidth = classWidth;
556   }
557
558   /**
559    * Get the width of the hostname field.
560    */

561   public int getHostWidth()
562   {
563     return this.hostWidth;
564   }
565
566   /**
567    * Set the width of the hostname field.
568    */

569   public void setHostWidth(int hostWidth)
570   {
571     this.hostWidth = hostWidth;
572   }
573
574   /**
575    * Get the width of the channel field.
576    */

577   public int getChannelWidth()
578   {
579     return this.channelWidth;
580   }
581
582   /**
583    * Set the width of the channel field.
584    */

585   public void setChannelWidth(int channelWidth)
586   {
587     this.channelWidth = channelWidth;
588   }
589
590   /**
591    * Get the width of the thread field.
592    */

593   public int getThreadWidth()
594   {
595     return this.threadWidth;
596   }
597
598   /**
599    * Set the width of the thread field.
600    */

601   public void setThreadWidth(int threadWidth)
602   {
603     this.threadWidth = threadWidth;
604   }
605
606   /**
607    * Justify text to given width in the buffer.
608    */

609   protected void justify(StringBuffer JavaDoc out, StringBuffer JavaDoc in, int width)
610   {
611     justify(out, in.toString(), width);
612   }
613
614   /**
615    * Justify text to given width in the buffer.
616    */

617   protected void justify(StringBuffer JavaDoc out, String JavaDoc in, int width)
618   {
619     out.append(in);
620     for (int i=in.length(); i<width; i++)
621         out.append(" ");
622   }
623 }
624
Popular Tags