KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > util > log > XMLCocoonLogFormatter


1 /*
2  * Copyright 1999-2004 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 package org.apache.cocoon.util.log;
17
18 import org.apache.avalon.framework.CascadingThrowable;
19 import org.apache.cocoon.environment.ObjectModelHelper;
20 import org.apache.cocoon.environment.Request;
21 import org.apache.commons.lang.ClassUtils;
22 import org.apache.commons.lang.SystemUtils;
23 import org.apache.log.ContextMap;
24 import org.apache.log.LogEvent;
25 import org.apache.log.Logger;
26 import org.apache.log.format.Formatter;
27
28 import java.io.StringWriter JavaDoc;
29 import java.text.SimpleDateFormat JavaDoc;
30 import java.util.Date JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.StringTokenizer JavaDoc;
33
34 /**
35  * A refactoring of <code>org.apache.log.format.PatternFormatter</code>
36  * and <code>org.apache.cocoon.util.log.CocoonLogFormatter</code> for
37  * producing XML format.
38  * This formater formats the LogEntries according to given input types. Each
39  * log entry is inside a &lt;log-entry&gt; element and each information is
40  * inside an own element.
41  *
42  * <ul>
43  * <li><code>class</code> : outputs the name of the class that has logged the
44  * message. The optional <code>short</code> subformat removes the
45  * package name. Warning : this pattern works only if formatting occurs in
46  * the same thread as the call to Logger, i.e. it won't work with
47  * <code>AsyncLogTarget</code>. The class name is embeded by a &lt;class&gt;
48  * element.</li>
49  * <li><code>thread</code> : outputs the name of the current thread (first element
50  * on the context stack). The thread name is surrounded by a &lt;thread&gt;
51  * element.</li>
52  * <li><code>uri</code> : outputs the request URI (&lt;uri&gt;).<li>
53  * <li><code>category</code> : outputs the log category (&lt;category&gt;).<li>
54  * <li><code>message</code> : outputs the message (&lt;message&gt;).<li>
55  * <li><code>time</code> : outputs the time (&lt;time&gt;).<li>
56  * <li><code>rtime</code> : outputs the relative time (&lt;relative-time&gt;).<li>
57  * <li><code>throwable</code> : outputs the exception (&lt;throwable&gt;).<li>
58  * <li><code>priority</code> : outputs the priority (&lt;priority&gt;).<li>
59  * <li><code>host</code> : outputs the request host header (&lt;priority&gt;).<li>
60  * </ul>
61  *
62  * @author <a HREF="mailto:donaldp@apache.org">Peter Donald</a>
63  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
64  * @author <a HREF="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
65  * @version CVS $Id: XMLCocoonLogFormatter.java 124756 2005-01-10 03:09:07Z antonio $
66  */

67 public class XMLCocoonLogFormatter implements Formatter {
68
69     protected final static String JavaDoc TYPE_CLASS_STR = "class";
70     protected final static String JavaDoc TYPE_CLASS_SHORT_STR = "short";
71
72     protected final static int TYPE_REQUEST_URI = 0;
73     protected final static int TYPE_CATEGORY = 1;
74     protected final static int TYPE_MESSAGE = 2;
75     protected final static int TYPE_TIME = 3;
76     protected final static int TYPE_RELATIVE_TIME = 4;
77     protected final static int TYPE_THROWABLE = 5;
78     protected final static int TYPE_PRIORITY = 6;
79     protected final static int TYPE_CLASS = 7;
80     protected final static int TYPE_CLASS_SHORT = 8;
81     protected final static int TYPE_THREAD = 9;
82     protected final static int TYPE_HOST = 10;
83
84     public final static String JavaDoc[] typeStrings = new String JavaDoc[] {
85          "uri", // 0
86
"category", // 1
87
"message", // 2
88
"time", // 3
89
"rtime", // 4
90
"throwable", // 5
91
"priority", // 6
92
"class", // 7
93
"class:short", // 8
94
"thread", // 9
95
"host"}; // 10
96

97     protected final SimpleDateFormat JavaDoc dateFormatter = new SimpleDateFormat JavaDoc("(yyyy-MM-dd) HH:mm.ss:SSS");
98
99     protected int[] types;
100
101     /**
102      * Format the event according to the pattern.
103      *
104      * @param event the event
105      * @return the formatted output
106      */

107     public String JavaDoc format( final LogEvent event ) {
108         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
109         sb.append("<log-entry>").append(SystemUtils.LINE_SEPARATOR);
110         final String JavaDoc value = this.getRequestId(event.getContextMap());
111         if (value != null) {
112             sb.append("<request-id>").append(value).append("</request-id>").append(SystemUtils.LINE_SEPARATOR);
113         }
114         for(int i = 0; i < this.types.length; i++) {
115             switch(this.types[i]) {
116                 case TYPE_REQUEST_URI:
117                     sb.append("<uri>");
118                     sb.append(this.getURI(event.getContextMap()));
119                     sb.append("</uri>").append(SystemUtils.LINE_SEPARATOR);
120                     break;
121                 case TYPE_CLASS:
122                     sb.append("<class>");
123                     sb.append(this.getClass(TYPE_CLASS));
124                     sb.append("</class>").append(SystemUtils.LINE_SEPARATOR);
125                     break;
126                 case TYPE_CLASS_SHORT:
127                     sb.append("<class>");
128                     sb.append(this.getClass(TYPE_CLASS_SHORT));
129                     sb.append("</class>").append(SystemUtils.LINE_SEPARATOR);
130                     break;
131                 case TYPE_THREAD:
132                     sb.append("<thread>");
133                     sb.append(this.getThread(event.getContextMap()));
134                     sb.append("</thread>").append(SystemUtils.LINE_SEPARATOR);
135                     break;
136                 case TYPE_RELATIVE_TIME:
137                     sb.append("<relative-time>");
138                     sb.append(event.getRelativeTime());
139                     sb.append("</relative-time>").append(SystemUtils.LINE_SEPARATOR);
140                     break;
141                 case TYPE_TIME:
142                     sb.append("<time>");
143                     sb.append(dateFormatter.format(new Date JavaDoc(event.getTime())));
144                     sb.append("</time>").append(SystemUtils.LINE_SEPARATOR);
145                     break;
146                 case TYPE_THROWABLE:
147                     Throwable JavaDoc throwable = event.getThrowable();
148                     if (throwable != null) {
149                         sb.append("<throwable><![CDATA[").append(SystemUtils.LINE_SEPARATOR);
150                         while (throwable != null) {
151                             final StringWriter JavaDoc sw = new StringWriter JavaDoc();
152                             throwable.printStackTrace( new java.io.PrintWriter JavaDoc( sw ) );
153                             sb.append(sw.toString());
154                             if (throwable instanceof CascadingThrowable ) {
155                                 throwable = ((CascadingThrowable)throwable).getCause();
156                             } else {
157                                 throwable = null;
158                             }
159                         }
160                         sb.append(SystemUtils.LINE_SEPARATOR).append("]]> </throwable>").append(SystemUtils.LINE_SEPARATOR);
161                     }
162                     break;
163                 case TYPE_MESSAGE:
164                     sb.append("<message><![CDATA[").append(SystemUtils.LINE_SEPARATOR);
165                     sb.append(event.getMessage());
166                     sb.append(SystemUtils.LINE_SEPARATOR).append("]]> </message>").append(SystemUtils.LINE_SEPARATOR);
167                     break;
168                 case TYPE_CATEGORY:
169                     sb.append("<category>");
170                     sb.append(event.getCategory());
171                     sb.append("</category>").append(SystemUtils.LINE_SEPARATOR);
172                     break;
173                 case TYPE_PRIORITY:
174                     sb.append("<priority>");
175                     sb.append(event.getPriority().getName());
176                     sb.append("</priority>").append(SystemUtils.LINE_SEPARATOR);
177                     break;
178                 case TYPE_HOST:
179                     sb.append("<host>");
180                     sb.append(getHost(event.getContextMap()));
181                     sb.append("</host>");
182                     break;
183             }
184         }
185         sb.append("</log-entry>");
186         sb.append(SystemUtils.LINE_SEPARATOR);
187         return sb.toString();
188     }
189
190     /**
191      * Find the URI that is being processed.
192      */

193     private String JavaDoc getURI(ContextMap ctxMap) {
194         String JavaDoc result = "Unknown-URI";
195
196         // Get URI from the the object model.
197
if (ctxMap != null) {
198             Object JavaDoc context = ctxMap.get("objectModel");
199             if (context != null &&context instanceof Map) {
200                 // Get the request
201
Request request = ObjectModelHelper.getRequest((Map)context);
202                 if (request != null) {
203                     result = request.getRequestURI();
204                 }
205             }
206         }
207         return result;
208     }
209
210     private String JavaDoc getHost(ContextMap ctxMap) {
211         String JavaDoc result = "Unknown-host";
212
213         if (ctxMap != null) {
214             Object JavaDoc context = ctxMap.get("objectModel");
215             if (context != null && context instanceof Map) {
216                 // Get the request
217
Request request = ObjectModelHelper.getRequest((Map)context);
218                 if (request != null) {
219                     result = request.getHeader("host");
220                 }
221             }
222         }
223         return result;
224     }
225     
226     /**
227      * Find the request id that is being processed.
228      */

229     private String JavaDoc getRequestId(ContextMap ctxMap) {
230         String JavaDoc result = null;
231
232         // Get URI from the the object model.
233
if (ctxMap != null) {
234             Object JavaDoc context = ctxMap.get("request-id");
235             if (context != null) {
236                 result = context.toString();
237             }
238         }
239         return result;
240     }
241
242     /**
243      * Finds the class that has called Logger.
244      */

245     private String JavaDoc getClass(int format) {
246
247         Class JavaDoc[] stack = this.callStack.get();
248
249         // Traverse the call stack in reverse order until we find a Logger
250
for (int i = stack.length-1; i >= 0; i--) {
251             if (this.loggerClass.isAssignableFrom(stack[i])) {
252
253                 // Found : the caller is the previous stack element
254
String JavaDoc className = stack[i+1].getName();
255
256                 // Handle optional format
257
if (format == TYPE_CLASS_SHORT) {
258                     className = ClassUtils.getShortClassName(className);
259                 }
260                 return className;
261             }
262         }
263
264         // No Logger found in call stack : can occur with AsyncLogTarget
265
// where formatting takes place in a different thread.
266
return "Unknown-class";
267     }
268
269     /**
270      * Find the thread that is logged this event.
271      */

272     private String JavaDoc getThread(ContextMap ctxMap) {
273         if (ctxMap != null && ctxMap.get("threadName") != null) {
274             return (String JavaDoc)ctxMap.get("threadName");
275         } else {
276             return "Unknown-thread";
277         }
278     }
279
280     /**
281      * Retrieve the type-id for a particular string.
282      *
283      * @param type the string
284      * @return the type-id
285      */

286     protected int getTypeIdFor(final String JavaDoc type) {
287         for (int index = 0; index < typeStrings.length; index++) {
288             if (type.equalsIgnoreCase(typeStrings[index])) {
289                 return index;
290             }
291         }
292         throw new IllegalArgumentException JavaDoc( "Unknown Type - " + type );
293     }
294
295     /**
296      * Set the types from an array of strings.
297      */

298     public void setTypes(String JavaDoc[] typeStrings) {
299         if (typeStrings != null) {
300             this.types = new int[typeStrings.length];
301             for (int i = 0; i < typeStrings.length; i++) {
302                 this.types[i] = this.getTypeIdFor(typeStrings[i]);
303             }
304         } else {
305             this.types = new int[0];
306         }
307     }
308
309     /**
310      * Set the types from a whitespace separated string
311      */

312     public void setTypes(String JavaDoc typeString) {
313         if (typeString == null) {
314             this.types = new int[0];
315         } else {
316             // this is not the best implementation, but it works...
317
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(typeString);
318             this.types = new int[st.countTokens()];
319             for (int i = 0; i < this.types.length; i++) {
320                 this.types[i] = this.getTypeIdFor(st.nextToken());
321             }
322         }
323     }
324
325     /** The class that we will search for in the call stack */
326     private Class JavaDoc loggerClass = Logger.class;
327     private CallStack callStack = new CallStack();
328
329     /**
330      * Hack to get the call stack as an array of classes. The
331      * SecurityManager class provides it as a protected method, so
332      * change it to public through a new method !
333      */

334     static public class CallStack extends SecurityManager JavaDoc
335     {
336         /**
337          * Returns the current execution stack as an array of classes.
338          * The length of the array is the number of methods on the execution
339          * stack. The element at index 0 is the class of the currently executing
340          * method, the element at index 1 is the class of that method's caller,
341          * and so on.
342          *
343          * @return current execution stack as an array of classes.
344          */

345         public Class JavaDoc[] get() {
346             return getClassContext();
347         }
348     }
349 }
350
Popular Tags