root/trunk/src/java/org/jcoderz/commons/logging/LogFileEntry.java

Revision 1299, 10.9 kB (checked in by amandel, 3 years ago)
  • Log formatter ignores the category field but now outputs the last 9 characters of the thread name. In case of a ordinary log record the the name of the logger thread is used. This might be wrong in certain setups but is correct in many cases. The fawkeZ loggable records the thread name of the thread that created the loggable instance which is the correct thread name in all cases. #58
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
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 */
33package org.jcoderz.commons.logging;
34
35import java.text.ParseException;
36import java.util.HashMap;
37import java.util.Map;
38
39import org.apache.commons.pool.ObjectPool;
40import org.apache.commons.pool.PoolableObjectFactory;
41import org.apache.commons.pool.impl.StackObjectPool;
42
43
44/**
45 * This class encapsulates the information of a log record being read from the
46 * log file.
47 * Note: This is not thread safe, one instance of this must not be used by
48 * several threads in parallel.
49 *
50 */
51public class LogFileEntry
52      extends LogItem
53{
54   private static final ObjectPool POOL = new StackObjectPool();
55
56   /* Sets the current entry level. Always the entry cursor of the root entry
57      should be used .*/
58   private LogFileEntry mEntryCursor;
59   private LogFileEntry mRootEntry = null;
60
61   private final Map mFormatMap = new HashMap();
62
63   // Flag whether this stack of log file entries has already encountered a
64   // stack trace line. This is set for the root element.
65   private boolean mMetStackTraceLine = false;
66
67   private final boolean mPooled;
68
69   private static final class LogFileEntryFactory
70         implements PoolableObjectFactory
71   {
72      /**
73       * Hide default constructor.
74       */
75      private LogFileEntryFactory ()
76      {
77         // nop
78      }
79
80      /** {@inheritDoc} */
81      public Object makeObject ()
82      {
83         return new LogFileEntry(true);
84      }
85
86      /** {@inheritDoc} */
87      public void destroyObject (Object arg0)
88      {
89         // nop
90      }
91
92      /** {@inheritDoc} */
93      public void activateObject (Object arg)
94      {
95         // nop
96      }
97
98      /**
99       * Passivates an instance of LogFileEntry before it is put back into the
100       * pool.
101       * This is indirectly called by entry.release(), so do not call
102       * entry.release() again, but release a nested entry.
103       *
104       * @param arg The LogFileEntry object to passivate.
105       *
106       * @see org.apache.commons.pool.PoolableObjectFactory#passivateObject(java.lang.Object)
107       */
108      public void passivateObject (final Object arg)
109      {
110         final LogFileEntry entry = (LogFileEntry) arg;
111         final LogFileEntry nested = (LogFileEntry) entry.getNestedItem();
112         entry.setNestedEntry(null);
113         entry.reset();
114         if (nested != null)
115         {
116            nested.release();
117         }
118      }
119
120      /**
121       * Validates the LogFileEntry instance, there is nothing to check.
122       *
123       * @param arg The LogFileEntry instance to validate.
124       *
125       * @return true
126       *
127       * @see org.apache.commons.pool.PoolableObjectFactory#validateObject(java.lang.Object)
128       */
129      public boolean validateObject (Object arg)
130      {
131         return true;
132      }
133   }
134
135   static
136   {
137      POOL.setFactory(new LogFileEntryFactory());
138   }
139
140   protected LogFileEntry ()
141   {
142      this(false);
143   }
144
145   /**
146    * Creates a new instance of this.
147    *
148    * @param pooled Flag whether this instance is under pool control.
149    */
150   private LogFileEntry (final boolean pooled)
151   {
152      mEntryCursor = this;
153      mRootEntry = this;
154      mPooled = pooled;
155   }
156
157   /**
158    * Gets a new instance of LogFileEntry. The object being returned should
159    * be reset by calling {@linkplain #release()} when it is not needed anymore.
160    *
161    * @return instance of this. Might be newly created or reused.
162    *
163    * @throws LoggingException if an error occurs.
164    */
165   static LogFileEntry getLogFileEntry ()
166   {
167      try
168      {
169         return (LogFileEntry) POOL.borrowObject();
170      }
171      catch (Exception ex)
172      {
173         throw new LoggingException(
174               "Error retrieving an instance of LogFileEntry", ex);
175      }
176   }
177
178   /**
179    * Adds a new line being read from the log file to this entry. The line is
180    * parsed and checked whether it belongs to this entry or to a new entry.
181    *
182    * @param logLine The line to add to this.
183    *
184    * @return true, if the line actually belongs to this; false, if it belongs
185    * to a new entry.
186    *
187    * @throws ParseException if an error occurs parsing the line.
188    * @throws Exception if a generic error occurs.
189    */
190   boolean addLogLine (final StringBuffer logLine)
191         throws ParseException
192   {
193      boolean rc = false;
194      LogLineFormat.LogLineType type = null;
195      if (logLine.length() == 0)
196      {
197         rc = true;
198      }
199      else
200      {
201         type = LogLineFormat.getLogLineType(logLine.charAt(0));
202         final LogFileEntry entry = findEntry(type);
203
204         if (entry != null)
205         {
206            entry.handleLogLine(type, logLine);
207            rc = true;
208         }
209      }
210      return rc;
211   }
212
213   /**
214    * Adds a String containing the string representation of a stacktrace item
215    * to the stacktrace stored by this. The stacktrace item could be a
216    * 'caused by' line, an 'at ...' or an '... nnn more' line.
217    *
218    * @param stackTraceElement The String containing the string representation
219    * of one element of the stack trace.
220    */
221   void addToStackTrace (final StackTraceInfo stackTraceElement)
222   {
223      if (stackTraceElement.isCauseLine())
224      {
225         // a nested element must exist in this case
226         if (getNestedItem() == null)
227         {
228            throw new LoggingException("Found a 'caused-by' stack trace line, "
229                  + "but have not got a nested element: "
230                  + stackTraceElement.toString());
231         }
232         setCurrentEntry((LogFileEntry) getNestedItem());
233      }
234      else
235      {
236         getStackTraceLines().add(stackTraceElement);
237      }
238   }
239
240   private LogFileEntry findEntry (final LogLineFormat.LogLineType type)
241   {
242      LogFileEntry entry = null;
243
244      if (type != LogLineFormat.STACKTRACE_MESSAGE)
245      {
246         /* if not a stack trace line and his stack has already read such a
247          * line, then it is for a new message. For test messages, where no
248          * stack trace might exist, the type must not be set, otherwise
249          * it is a new message. */
250         if (! mRootEntry.mMetStackTraceLine
251               && ((getCurrentEntry().getType() == null)
252                  || (type != LogLineFormat.TRACE_MESSAGE
253                        && type != LogLineFormat.EXCEPTION_MESSAGE
254                        && type != LogLineFormat.LOG_MESSAGE
255                        && type != LogLineFormat.ERROR_MESSAGE)))
256         {
257            entry = getCurrentEntry();
258         }
259      }
260      else
261      {
262         if (! mRootEntry.mMetStackTraceLine)
263         {
264            // first stack trace line starts from root entry again.
265            entry = mRootEntry;
266            setCurrentEntry(entry);
267            mRootEntry.mMetStackTraceLine = true;
268         }
269         else
270         {
271            entry = getCurrentEntry();
272         }
273      }
274      return entry;
275   }
276
277   private LogLineFormat getFormat (final LogLineFormat.LogLineType type)
278   {
279      LogLineFormat rc = (LogLineFormat) mFormatMap.get(type);
280      if (rc == null)
281      {
282         rc = LogLineFormatFactory.create(type);
283         mFormatMap .put(type, rc);
284      }
285      return rc;
286   }
287
288   private void handleLogLine (
289         final LogLineFormat.LogLineType type,
290         final StringBuffer sb)
291         throws ParseException
292   {
293      if ((type == LogLineFormat.TRACE_MESSAGE)
294            || (type == LogLineFormat.LOG_MESSAGE)
295            || (type == LogLineFormat.EXCEPTION_MESSAGE)
296            || (type == LogLineFormat.ERROR_MESSAGE))
297      {
298         setType(String.valueOf(type.getTypeSpecifier()));
299      }
300      if (type == LogLineFormat.NESTED_MESSAGE)
301      {
302         final LogFileEntry entry = LogFileEntry.getLogFileEntry();
303         setCurrentEntry(entry);
304         setNestedEntry(entry);
305         getFormat(type).parse(sb, entry);
306      }
307      else
308      {
309         getFormat(type).parse(sb, this);
310      }
311   }
312
313   /**
314    * Used for resetting this to an initial state so that this object could be
315    * reused again.
316    * Releases the nested entry, if there is such.
317    *
318    * @throws LoggingException if an error occurs.
319    */
320   public void reset ()
321         throws LoggingException
322   {
323      final LogFileEntry nested = (LogFileEntry) getNestedItem();
324      super.reset();
325      mEntryCursor = this;
326      mMetStackTraceLine = false;
327      mRootEntry = this;
328
329      if (nested != null)
330      {
331         nested.release();
332      }
333   }
334
335   /**
336    * By calling this a client signals he has finished using this instance. This
337    * should be called for each instance not in use anymore.
338    * Releases the nested entry as well, if there is such.
339    *
340    * @throws LoggingException if an error occurs.
341    */
342   void release ()
343         throws LoggingException
344   {
345      try
346      {
347         reset();
348         if (mPooled)
349         {
350            POOL.returnObject(this);
351         }
352      }
353      catch (Exception ex)
354      {
355         throw new LoggingException("Error releasing this " + this, ex);
356      }
357   }
358
359   /**
360    * Sets the supplied entry as nested entry for this and this as parent for
361    * the supplied entry.
362    *
363    * @param nestedEntry The LogFileEntry to set as nested entry for this.
364    */
365   private void setNestedEntry (final LogFileEntry nestedEntry)
366   {
367      nestedEntry.mRootEntry = this.mRootEntry;
368      setNestedItem(nestedEntry);
369   }
370
371   private LogFileEntry getCurrentEntry ()
372   {
373      return mRootEntry.mEntryCursor;
374   }
375
376   private void setCurrentEntry (final LogFileEntry entry)
377   {
378      mRootEntry.mEntryCursor = entry;
379   }
380
381}
Note: See TracBrowser for help on using the browser.