Project Report: fawkez

Packagesummary org.jcoderz.commons

org.jcoderz.commons.LogFormatter

LineHitsNoteSource
1  /*
2   * $Id: LogFormatter.java 1577 2009-12-07 15:44:44Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons;
34  
35  
36  import java.util.ArrayList;
37  import java.util.HashMap;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.logging.Formatter;
41  import java.util.logging.LogRecord;
42  import java.util.logging.Logger;
43  
44  import org.jcoderz.commons.logging.LogLineFormat;
45  import org.jcoderz.commons.logging.LogLineFormatFactory;
46  
47  /**
48   * This type implements a Formatter to be used for logging in a format, which
49   * allows filtering of log files with standard tools and little effort. It
50   * formats both standard a {@link java.util.logging.LogRecord} and instances of
51   * {@link org.jcoderz.commons.Loggable}.
52   *
53   */
54100(1)public class LogFormatter
55        extends Formatter
56  {
57      /**
58       * Name of the logger that controls which log level is needed as minimum 
59       * to trigger stack traces with log messages.
60       */
61      public static final String MSG_LOGGER_STACK_TRACE = "msgLoggerStackTrace";
62100     private static final Logger FWK_TRACE_LOGGER_LOGGER
63          = Logger.getLogger(MSG_LOGGER_STACK_TRACE);
64100     private final ThreadLocal mMessageFormatters = new ThreadLocal();
65  
66     /** {@inheritDoc} */
67     public String format (LogRecord record)
68     {
69100       final StringBuffer sb = new StringBuffer();
70100       Loggable loggable = null;
71100       if (record.getParameters() != null && record.getParameters().length > 0)
72        {
73100          if (record.getParameters()[0] instanceof Loggable)
74           {
75100             loggable = (Loggable) record.getParameters()[0];
76           }
77        }
78100       format(sb, record, loggable);
79100       return sb.toString();
80     }
81  
82     /**
83      * Gets the message format for a log line with <code>type</code> as type
84      * specifier.
85      *
86      * @param type The type specifier for the requested message format.
87      *
88      * @return MessageFormat for log line of type <code>type</code>
89      */
90     private LogLineFormat getMessageFormat (
91           final LogLineFormat.LogLineType type)
92     {
93100       Map formatters = (Map) mMessageFormatters.get();
94100       if (formatters == null)
95        {
96100          formatters = createMessageFormats();
97100          mMessageFormatters.set(formatters);
98        }
99100       return (LogLineFormat) formatters.get(type);
100     }
101  
102     private Map createMessageFormats ()
103     {
104100       final Map rc = new HashMap();
105  
106100       addMessageFormat(rc, LogLineFormat.TRACE_MESSAGE);
107100       addMessageFormat(rc, LogLineFormat.EXCEPTION_MESSAGE);
108100       addMessageFormat(rc, LogLineFormat.LOG_MESSAGE);
109100       addMessageFormat(rc, LogLineFormat.ERROR_MESSAGE);
110100       addMessageFormat(rc, LogLineFormat.STACKTRACE_MESSAGE);
111100       addMessageFormat(rc, LogLineFormat.PARAMETER_LINE);
112100       addMessageFormat(rc, LogLineFormat.NESTED_MESSAGE);
113  
114100       return rc;
115     }
116  
117     /**
118      * Formats a LogRecord, which does not carry any parameters. In this case it
119      * is a trace record, not a Loggable is logged.
120      *
121      * @param sb the StringBuffer where to append the formatted log record
122      * @param record the log record to format
123      * @param trackingIdSequence a list collecting all tracking ids of messages
124      * being formatted by one call.
125      */
126     private void formatLogRecord (
127           final StringBuffer sb,
128           final LogRecord record,
129           final List trackingIdSequence)
130     {
131        LogLineFormat.LogLineType type;
132100       if (record.getThrown() != null)
133        {
134100          type = LogLineFormat.EXCEPTION_MESSAGE;
135        }
136        else
137        {
138100          type = LogLineFormat.TRACE_MESSAGE;
139        }
140100       final LogLineFormat format = getMessageFormat(type);
141100       format.format(sb, record, null, trackingIdSequence, null, null);
142100    }
143  
144     /**
145      * Appends a full stack trace carried by the supplied LogRecord or Loggable
146      * to the string buffer. If neither of them carries a Throwable, nothing is
147      * done here. The stack trace appended by this contains the complete chain
148      * of throwables.
149      *
150      * @param sb the StringBuffer to which to append the stack trace
151      * @param record The LogRecord
152      * @param loggable the Loggable, might be null.
153      * @param trackingIdSequence the list collecting the sequence of tracking
154      * ids, must not be null.
155      */
156     private void appendStackTrace (
157           final StringBuffer sb,
158           final LogRecord record,
159           final Loggable loggable,
160           final List trackingIdSequence)
161     {
162100       Throwable thrown = getTopLevelThrown(record, loggable);
163100       Throwable outerTrace = null;
164100       final LogLineFormat.LogLineType type = LogLineFormat.STACKTRACE_MESSAGE;
165100       final LogLineFormat format = getMessageFormat(type);
166100       while (thrown != null)
167        {
168100          if (thrown instanceof Loggable)
169           {
170100             addTrackingNumber(trackingIdSequence, (Loggable) thrown);
171           }
172100          format.format(sb, record, loggable, trackingIdSequence,
173                 thrown, outerTrace);
174100          outerTrace = thrown;
175100          thrown = outerTrace.getCause();
176        }
177100    }
178  
179     /**
180      * Appends the parameters carried by the supplied LogRecord or Loggable
181      * to the string buffer. If there are no parameters, nothing is done here.
182      *
183      * @param sb the StringBuffer to which to append the stack trace
184      * @param loggable the Loggable, might be null.
185      * @param trackingIdSequence the list collecting the sequence of tracking
186      * ids, must not be null.
187      */
188     private void appendParameters (
189           final StringBuffer sb,
190           final LogRecord record,
191           final Loggable loggable,
192           final List trackingIdSequence)
193     {
194100       final LogLineFormat.LogLineType type = LogLineFormat.PARAMETER_LINE;
195100       final LogLineFormat format = getMessageFormat(type);
196100       format.format(sb, record, loggable, trackingIdSequence, null, null);
197100    }
198  
199     /**
200      * This loops through the nested Loggables/throwables and formats the
201      * complete message stack.
202      *
203      * @param sb The StringBuffer where to append the formatted message stack.
204      * @param record The source LogRecord to format
205      * @param loggable The first instance of Loggable, might be null if
206      * <code>record</code> does not carry a Loggable.
207      */
208     private void format (
209           final StringBuffer sb,
210           final LogRecord record,
211           final Loggable loggable)
212     {
213100       List trackingIds = initialiseTrackingIds(record, loggable);
214100       Loggable currentLoggable = loggable;
215100       boolean isFirst = true;
216  
217100       Throwable cause = null;
218100       while (isFirst || (! ((currentLoggable == null) && (cause == null))))
219        {
220100          Throwable nestedCause = null;
221100          if (currentLoggable != null)
222           {
223100             formatLoggable(sb, record, currentLoggable, trackingIds);
224100             nestedCause = currentLoggable.getCause();
225           }
226100          else if (isFirst)
227           {
228100             formatLogRecord(sb, record, trackingIds);
229100             nestedCause = record.getThrown();
230           }
231100          isFirst = false;
232100          cause = (cause != null) ? cause.getCause() : nestedCause;
233100          currentLoggable = null;
234  
235100          if (cause != null)
236           {
237100             appendNestingLevel(sb, record, cause, trackingIds);
238100             if (cause instanceof Loggable)
239              {
240100                currentLoggable = (Loggable) cause;
241              }
242           }
243100       }
244        // for messages: do not log stack traces for log messages of level
245        // below the FWK_TRACE_LOGGER_LOGGER log level.
246100       if (!(loggable instanceof LogEvent)
247            || FWK_TRACE_LOGGER_LOGGER.isLoggable(record.getLevel()))
248        {
249100           trackingIds = initialiseTrackingIds(record, loggable);
250100           appendStackTrace(sb, record, loggable, trackingIds);
251        }
252100    }
253  
254     private void formatLoggable (
255           final StringBuffer sb,
256           final LogRecord record,
257           final Loggable loggable,
258           final List trackingIds)
259     {
260100       final LogLineFormat.LogLineType type = determineType(loggable);
261100       final LogLineFormat format = getMessageFormat(type);
262100       format.format(sb, record, loggable, trackingIds, null, null);
263100       appendParameters(sb, record, loggable, trackingIds);
264100    }
265  
266     /**
267      * Creates the message format for the specified type and adds it to the
268      * supplied map.
269      *
270      * @param msgFormats The map to which to add the new message format with
271      * <code>type</code> as key.
272      * @param type The type for which to create the format and add to the map.
273      */
274     private void addMessageFormat (
275           final Map msgFormats,
276           final LogLineFormat.LogLineType type)
277     {
278100       final LogLineFormat format = LogLineFormatFactory.create(type);
279100       msgFormats.put(type, format);
280100    }
281  
282     /**
283      * Determines the log line type for the supplied Loggable.
284      *
285      * @param loggable The Loggable for which to determine the logline type.
286      *
287      * @return The correct LogLineType for <code>loggable</code>.
288      *
289      * @see LogLineType
290      */
291     private LogLineFormat.LogLineType determineType (final Loggable loggable)
292     {
293        final Throwable cause;
294        final LogLineFormat.LogLineType rc;
295  
296100       if (loggable instanceof Throwable)
297        {
298100          cause = (Throwable) loggable;
299        }
300        else
301        {
3020          cause = loggable.getCause();
303        }
304100       if ((cause != null) && ! (cause instanceof LogEvent))
305        {
306100          rc = LogLineFormat.ERROR_MESSAGE;
307        }
308        else
309        {
310100          rc = LogLineFormat.LOG_MESSAGE;
311        }
312100       return rc;
313     }
314  
315    /**
316     * Appends a nesting level to the StringBuffer. This is performed if the
317     * current Loggable carries a cause, which might be a Loggable itself.
318     * In case the cause is a Loggable, the tracking id sequence is extended with
319     * its tracking id and the symbol name is logged here. If the cause is not a
320     * Loggable, its name and message are logged.
321     *
322     * @param sb The StringBuffer where to append the nesting level.
323     * @param record The LogRecord currently formatted.
324     * @param cause The Throwable causing the nesting level.
325     * @param trackingIdSequence The list collecting the sequence of tracking ids.
326     */
327     private void appendNestingLevel (
328           final StringBuffer sb,
329           final LogRecord record,
330           final Throwable cause,
331           final List trackingIdSequence)
332     {
333        final Loggable loggable;
334100       if (cause instanceof Loggable)
335        {
336100          loggable = (Loggable) cause;
337        }
338        else
339        {
340100          loggable = null;
341        }
342100       final LogLineFormat.LogLineType type = LogLineFormat.NESTED_MESSAGE;
343100       final LogLineFormat format = getMessageFormat(type);
344100       if (loggable == null)
345        {
346100          format.format(sb, record, null, trackingIdSequence, null, cause);
347        }
348        else
349        {
350100          addTrackingNumber(trackingIdSequence, loggable);
351100          format.format(sb, record, loggable, trackingIdSequence, null,
352                 loggable.getLogMessageInfo().getSymbol());
353        }
354100    }
355  
356     /**
357      * Initialises the list holding the sequence of tracking ids. Creates a new
358      * list and fills it with the first tracking id, which is taken from the
359      * supplied loggable. If this is null, the sequence number of the supplied
360      * log record is taken.
361      *
362      * @param record The log record to format. Must not be null.
363      * @param loggable The loggable being encapsulated by <code>record</code>,
364      * might be null.
365      *
366      * @return List with first tracking id.
367      */
368     private List initialiseTrackingIds (
369           final LogRecord record,
370           final Loggable loggable)
371     {
372100       final List rc = new ArrayList();
373  
374100       if (loggable != null)
375        {
376100          addTrackingNumber(rc, loggable);
377        }
378        else
379        {
380100          addTrackingNumber(rc, record);
381        }
382100       return rc;
383     }
384  
385     /**
386      * Adds the record's sequence number as new tracking id to the sequence of
387      * tracking ids, if it is not already included as last element.
388      *
389      * @param trackingIds The list storing the sequence of tracking ids.
390      * @param record The record for which to add the sequence number.
391      */
392     private void addTrackingNumber (
393           final List trackingIds,
394           final LogRecord record)
395     {
396100       addTrackingNumber(trackingIds,
397              Integer.toHexString((int) record.getSequenceNumber()));
398100    }
399  
400     /**
401      * Adds the loggable's tracking number as new tracking id to the sequence of
402      * tracking ids, if it is not already included as last element.
403      *
404      * @param trackingIds The list storing the sequence of tracking ids.
405      * @param loggable The Loggable for which to add the tracking number.
406      */
407     private void addTrackingNumber (
408           final List trackingIds,
409           final Loggable loggable)
410     {
411100       addTrackingNumber(trackingIds, loggable.getTrackingNumber());
412100    }
413  
414     /**
415      * Adds the new tracking number as new tracking id to the sequence of
416      * tracking ids, if it is not already included as last element.
417      *
418      * @param trackingIds The list storing the sequence of tracking ids.
419      * @param newId The number to add to the sequence.
420      */
421     private void addTrackingNumber (
422           final List trackingIds,
423           final String newId)
424     {
425100       if (! trackingIds.isEmpty())
426        {
427100          if (! trackingIds.get(trackingIds.size() - 1).equals(newId))
428           {
429100             trackingIds.add(newId);
430           }
431        }
432        else
433        {
434100          trackingIds.add(newId);
435        }
436100    }
437  
438     /**
439      * Gets the top level throwable from the supplied LogRecord and Loggable.
440      * This is either the cause of <code>record or loggable</code> or
441      * <code>loggable</code> itself.
442      *
443      * @param record The LogRecord currently formatted.
444      * @param loggable The Loggable carried by <code>record</code>
445      *
446      * @return top level Throwable, might be null if no such.
447      */
448     private Throwable getTopLevelThrown (
449           final LogRecord record,
450           final Loggable loggable)
451     {
452        final Throwable thrown;
453  
454100       if (loggable == null)
455        {
456100          thrown = record.getThrown();
457        }
458        else
459        {
460100          if (loggable instanceof Throwable)
461           {
462100             thrown = (Throwable) loggable;
463           }
464           else
465           {
4660             thrown = loggable.getCause();
467           }
468        }
469100       return thrown;
470     }
471  }

Findings in this File

c (1) 54 : 0 Type Javadoc comment is missing an @author tag.