KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log4j > spi > LoggingEvent


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.spi;
18
19 import org.apache.log4j.*;
20
21 import org.apache.log4j.helpers.LogLog;
22 import org.apache.log4j.helpers.Loader;
23 import java.lang.reflect.Method JavaDoc;
24 import java.io.ObjectOutputStream JavaDoc;
25 import java.io.ObjectInputStream JavaDoc;
26 import java.util.Hashtable JavaDoc;
27
28 // Contributors: Nelson Minar <nelson@monkey.org>
29
// Wolf Siberski
30
// Anders Kristensen <akristensen@dynamicsoft.com>
31

32 /**
33    The internal representation of logging events. When an affirmative
34    decision is made to log then a <code>LoggingEvent</code> instance
35    is created. This instance is passed around to the different log4j
36    components.
37
38    <p>This class is of concern to those wishing to extend log4j.
39
40    @author Ceki G&uuml;lc&uuml;
41    @author James P. Cakalic
42
43    @since 0.8.2 */

44 public class LoggingEvent implements java.io.Serializable JavaDoc {
45
46   private static long startTime = System.currentTimeMillis();
47
48   /** Fully qualified name of the calling category class. */
49   transient public final String JavaDoc fqnOfCategoryClass;
50
51   /**
52    * The category of the logging event. This field is not serialized
53    * for performance reasons.
54    *
55    * <p>It is set by the LoggingEvent constructor or set by a remote
56    * entity after deserialization.
57    *
58    * @deprecated This field will be marked as private or be completely
59    * removed in future releases. Please do not use it.
60    * */

61   transient private Category logger;
62
63   /**
64    * <p>The category (logger) name.
65    *
66    * @deprecated This field will be marked as private in future
67    * releases. Please do not access it directly. Use the {@link
68    * #getLoggerName} method instead.
69
70    * */

71   final public String JavaDoc categoryName;
72
73   /**
74    * Level of logging event. Level cannot be serializable because it
75    * is a flyweight. Due to its special seralization it cannot be
76    * declared final either.
77    *
78    * <p> This field should not be accessed directly. You shoud use the
79    * {@link #getLevel} method instead.
80    *
81    * @deprecated This field will be marked as private in future
82    * releases. Please do not access it directly. Use the {@link
83    * #getLevel} method instead.
84    * */

85   transient public Priority level;
86
87   /** The nested diagnostic context (NDC) of logging event. */
88   private String JavaDoc ndc;
89
90   /** The mapped diagnostic context (MDC) of logging event. */
91   private Hashtable JavaDoc mdcCopy;
92
93
94   /** Have we tried to do an NDC lookup? If we did, there is no need
95    * to do it again. Note that its value is always false when
96    * serialized. Thus, a receiving SocketNode will never use it's own
97    * (incorrect) NDC. See also writeObject method. */

98   private boolean ndcLookupRequired = true;
99
100
101   /** Have we tried to do an MDC lookup? If we did, there is no need
102    * to do it again. Note that its value is always false when
103    * serialized. See also the getMDC and getMDCCopy methods. */

104   private boolean mdcCopyLookupRequired = true;
105
106   /** The application supplied message of logging event. */
107   transient private Object JavaDoc message;
108
109   /** The application supplied message rendered through the log4j
110       objet rendering mechanism.*/

111   private String JavaDoc renderedMessage;
112
113   /** The name of thread in which this logging event was generated. */
114   private String JavaDoc threadName;
115
116
117   /** This
118       variable contains information about this event's throwable
119   */

120   private ThrowableInformation throwableInfo;
121
122   /** The number of milliseconds elapsed from 1/1/1970 until logging event
123       was created. */

124   public final long timeStamp;
125   /** Location information for the caller. */
126   private LocationInfo locationInfo;
127
128   // Serialization
129
static final long serialVersionUID = -868428216207166145L;
130
131   static final Integer JavaDoc[] PARAM_ARRAY = new Integer JavaDoc[1];
132   static final String JavaDoc TO_LEVEL = "toLevel";
133   static final Class JavaDoc[] TO_LEVEL_PARAMS = new Class JavaDoc[] {int.class};
134   static final Hashtable JavaDoc methodCache = new Hashtable JavaDoc(3); // use a tiny table
135

136   /**
137      Instantiate a LoggingEvent from the supplied parameters.
138
139      <p>Except {@link #timeStamp} all the other fields of
140      <code>LoggingEvent</code> are filled when actually needed.
141      <p>
142      @param logger The logger generating this event.
143      @param level The level of this event.
144      @param message The message of this event.
145      @param throwable The throwable of this event. */

146   public LoggingEvent(String JavaDoc fqnOfCategoryClass, Category logger,
147               Priority level, Object JavaDoc message, Throwable JavaDoc throwable) {
148     this.fqnOfCategoryClass = fqnOfCategoryClass;
149     this.logger = logger;
150     this.categoryName = logger.getName();
151     this.level = level;
152     this.message = message;
153     if(throwable != null) {
154       this.throwableInfo = new ThrowableInformation(throwable);
155     }
156     timeStamp = System.currentTimeMillis();
157   }
158
159   /**
160      Instantiate a LoggingEvent from the supplied parameters.
161
162      <p>Except {@link #timeStamp} all the other fields of
163      <code>LoggingEvent</code> are filled when actually needed.
164      <p>
165      @param logger The logger generating this event.
166      @param timeStamp the timestamp of this logging event
167      @param level The level of this event.
168      @param message The message of this event.
169      @param throwable The throwable of this event. */

170   public LoggingEvent(String JavaDoc fqnOfCategoryClass, Category logger,
171               long timeStamp, Priority level, Object JavaDoc message,
172               Throwable JavaDoc throwable) {
173     this.fqnOfCategoryClass = fqnOfCategoryClass;
174     this.logger = logger;
175     this.categoryName = logger.getName();
176     this.level = level;
177     this.message = message;
178     if(throwable != null) {
179       this.throwableInfo = new ThrowableInformation(throwable);
180     }
181
182     this.timeStamp = timeStamp;
183   }
184
185   /**
186      Set the location information for this logging event. The collected
187      information is cached for future use.
188    */

189   public LocationInfo getLocationInformation() {
190     if(locationInfo == null) {
191       locationInfo = new LocationInfo(new Throwable JavaDoc(), fqnOfCategoryClass);
192     }
193     return locationInfo;
194   }
195
196   /**
197    * Return the level of this event. Use this form instead of directly
198    * accessing the <code>level</code> field. */

199   public Level getLevel() {
200     return (Level) level;
201   }
202
203   /**
204    * Return the name of the logger. Use this form instead of directly
205    * accessing the <code>categoryName</code> field.
206    */

207   public String JavaDoc getLoggerName() {
208     return categoryName;
209   }
210
211   /**
212      Return the message for this logging event.
213
214      <p>Before serialization, the returned object is the message
215      passed by the user to generate the logging event. After
216      serialization, the returned value equals the String form of the
217      message possibly after object rendering.
218
219      @since 1.1 */

220   public
221   Object JavaDoc getMessage() {
222     if(message != null) {
223       return message;
224     } else {
225       return getRenderedMessage();
226     }
227   }
228
229   /**
230    * This method returns the NDC for this event. It will return the
231    * correct content even if the event was generated in a different
232    * thread or even on a different machine. The {@link NDC#get} method
233    * should <em>never</em> be called directly. */

234   public
235   String JavaDoc getNDC() {
236     if(ndcLookupRequired) {
237       ndcLookupRequired = false;
238       ndc = NDC.get();
239     }
240     return ndc;
241   }
242
243
244   /**
245       Returns the the context corresponding to the <code>key</code>
246       parameter. If there is a local MDC copy, possibly because we are
247       in a logging server or running inside AsyncAppender, then we
248       search for the key in MDC copy, if a value is found it is
249       returned. Otherwise, if the search in MDC copy returns a null
250       result, then the current thread's <code>MDC</code> is used.
251       
252       <p>Note that <em>both</em> the local MDC copy and the current
253       thread's MDC are searched.
254
255   */

256   public
257   Object JavaDoc getMDC(String JavaDoc key) {
258     Object JavaDoc r;
259     // Note the mdcCopy is used if it exists. Otherwise we use the MDC
260
// that is associated with the thread.
261
if(mdcCopy != null) {
262       r = mdcCopy.get(key);
263       if(r != null) {
264         return r;
265       }
266     }
267     return MDC.get(key);
268   }
269
270   /**
271      Obtain a copy of this thread's MDC prior to serialization or
272      asynchronous logging.
273   */

274   public
275   void getMDCCopy() {
276     if(mdcCopyLookupRequired) {
277       mdcCopyLookupRequired = false;
278       // the clone call is required for asynchronous logging.
279
// See also bug #5932.
280
Hashtable JavaDoc t = (Hashtable JavaDoc) MDC.getContext();
281       if(t != null) {
282     mdcCopy = (Hashtable JavaDoc) t.clone();
283       }
284     }
285   }
286
287   public
288   String JavaDoc getRenderedMessage() {
289      if(renderedMessage == null && message != null) {
290        if(message instanceof String JavaDoc)
291      renderedMessage = (String JavaDoc) message;
292        else {
293      LoggerRepository repository = logger.getLoggerRepository();
294
295      if(repository instanceof RendererSupport) {
296        RendererSupport rs = (RendererSupport) repository;
297        renderedMessage= rs.getRendererMap().findAndRender(message);
298      } else {
299        renderedMessage = message.toString();
300      }
301        }
302      }
303      return renderedMessage;
304   }
305
306   /**
307      Returns the time when the application started, in milliseconds
308      elapsed since 01.01.1970. */

309   public static long getStartTime() {
310     return startTime;
311   }
312
313   public
314   String JavaDoc getThreadName() {
315     if(threadName == null)
316       threadName = (Thread.currentThread()).getName();
317     return threadName;
318   }
319
320   /**
321      Returns the throwable information contained within this
322      event. May be <code>null</code> if there is no such information.
323
324      <p>Note that the {@link Throwable} object contained within a
325      {@link ThrowableInformation} does not survive serialization.
326
327      @since 1.1 */

328   public
329   ThrowableInformation getThrowableInformation() {
330     return throwableInfo;
331   }
332
333   /**
334      Return this event's throwable's string[] representaion.
335   */

336   public
337   String JavaDoc[] getThrowableStrRep() {
338
339     if(throwableInfo == null)
340       return null;
341     else
342       return throwableInfo.getThrowableStrRep();
343   }
344
345
346   private
347   void readLevel(ObjectInputStream JavaDoc ois)
348                       throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
349
350     int p = ois.readInt();
351     try {
352       String JavaDoc className = (String JavaDoc) ois.readObject();
353       if(className == null) {
354     level = Level.toLevel(p);
355       } else {
356     Method JavaDoc m = (Method JavaDoc) methodCache.get(className);
357     if(m == null) {
358       Class JavaDoc clazz = Loader.loadClass(className);
359       // Note that we use Class.getDeclaredMethod instead of
360
// Class.getMethod. This assumes that the Level subclass
361
// implements the toLevel(int) method which is a
362
// requirement. Actually, it does not make sense for Level
363
// subclasses NOT to implement this method. Also note that
364
// only Level can be subclassed and not Priority.
365
m = clazz.getDeclaredMethod(TO_LEVEL, TO_LEVEL_PARAMS);
366       methodCache.put(className, m);
367     }
368     PARAM_ARRAY[0] = new Integer JavaDoc(p);
369     level = (Level) m.invoke(null, PARAM_ARRAY);
370       }
371     } catch(Exception JavaDoc e) {
372     LogLog.warn("Level deserialization failed, reverting to default.", e);
373     level = Level.toLevel(p);
374     }
375   }
376
377   private void readObject(ObjectInputStream JavaDoc ois)
378                         throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
379     ois.defaultReadObject();
380     readLevel(ois);
381
382     // Make sure that no location info is available to Layouts
383
if(locationInfo == null)
384       locationInfo = new LocationInfo(null, null);
385   }
386
387   private
388   void writeObject(ObjectOutputStream JavaDoc oos) throws java.io.IOException JavaDoc {
389     // Aside from returning the current thread name the wgetThreadName
390
// method sets the threadName variable.
391
this.getThreadName();
392
393     // This sets the renders the message in case it wasn't up to now.
394
this.getRenderedMessage();
395
396     // This call has a side effect of setting this.ndc and
397
// setting ndcLookupRequired to false if not already false.
398
this.getNDC();
399
400     // This call has a side effect of setting this.mdcCopy and
401
// setting mdcLookupRequired to false if not already false.
402
this.getMDCCopy();
403
404     // This sets the throwable sting representation of the event throwable.
405
this.getThrowableStrRep();
406
407     oos.defaultWriteObject();
408
409     // serialize this event's level
410
writeLevel(oos);
411   }
412
413   private
414   void writeLevel(ObjectOutputStream JavaDoc oos) throws java.io.IOException JavaDoc {
415
416     oos.writeInt(level.toInt());
417
418     Class JavaDoc clazz = level.getClass();
419     if(clazz == Level.class) {
420       oos.writeObject(null);
421     } else {
422       // writing directly the Class object would be nicer, except that
423
// serialized a Class object can not be read back by JDK
424
// 1.1.x. We have to resort to this hack instead.
425
oos.writeObject(clazz.getName());
426     }
427   }
428
429 }
430
Popular Tags