KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.apache.cocoon.util.log;
17
18 import java.util.Map JavaDoc;
19
20 import org.apache.avalon.framework.logger.LogKitLogger;
21 import org.apache.cocoon.environment.ObjectModelHelper;
22 import org.apache.cocoon.environment.Request;
23 import org.apache.cocoon.util.location.LocatedException;
24 import org.apache.commons.lang.ClassUtils;
25 import org.apache.commons.lang.exception.ExceptionUtils;
26 import org.apache.commons.lang.time.FastDateFormat;
27 import org.apache.log.ContextMap;
28 import org.apache.log.LogEvent;
29 import org.apache.log.Logger;
30
31 /**
32  * An extended pattern formatter. New patterns defined by this class are:
33  * <ul>
34  * <li><code>class</code>: Outputs the name of the class that has logged the
35  * message. The optional <code>short</code> subformat removes the
36  * package name. Warning: This pattern works only if formatting occurs in
37  * the same thread as the call to Logger, i.e. it won't work with
38  * <code>AsyncLogTarget</code>.</li>
39  * <li><code>uri</code>: Outputs the request URI.</li>
40  * <li><code>query</code>: Outputs the request query string</li>
41  * <li><code>thread</code>: Outputs the name of the current thread (first element
42  * on the context stack).</li>
43  * <li><code>host</code>: Outputs the request host header.<li>
44  * <li><code>rootThrowable</code>: Outputs the root throwable message and
45  * stacktrace.<li>
46  * </ul>
47  *
48  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
49  * @author <a HREF="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
50  * @version $Id: CocoonLogFormatter.java 326716 2005-10-19 21:44:41Z sylvain $
51  */

52 public class CocoonLogFormatter extends ExtensiblePatternFormatter
53 {
54     /**
55      * The constant defining the default stack depth when
56      * none other is specified.
57      */

58     public static final int DEFAULT_STACK_DEPTH = 8;
59
60     protected final static int TYPE_CLASS = MAX_TYPE + 1;
61     protected final static int TYPE_URI = MAX_TYPE + 2;
62     protected final static int TYPE_THREAD = MAX_TYPE + 3;
63     protected final static int TYPE_HOST = MAX_TYPE + 4;
64     protected final static int TYPE_QUERY = MAX_TYPE + 5;
65     protected final static int TYPE_ROOTTHROWABLE = MAX_TYPE + 6;
66
67     protected final static String JavaDoc TYPE_CLASS_STR = "class";
68     protected final static String JavaDoc TYPE_CLASS_SHORT_STR = "short";
69
70     protected final static String JavaDoc TYPE_URI_STR = "uri";
71     protected final static String JavaDoc TYPE_THREAD_STR = "thread";
72     protected final static String JavaDoc TYPE_HOST_STR = "host";
73     protected final static String JavaDoc TYPE_QUERY_STR = "query";
74     protected final static String JavaDoc TYPE_ROOTTHROWABLE_STR = "rootThrowable";
75
76     private static final String JavaDoc DEFAULT_TIME_PATTERN = "(yyyy-MM-dd) HH:mm.ss:SSS";
77     private static final FastDateFormat dateFormatter = FastDateFormat.getInstance(DEFAULT_TIME_PATTERN);
78
79     /**
80      * Hack to get the call stack as an array of classes. The
81      * SecurityManager class provides it as a protected method, so
82      * change it to public through a new method !
83      */

84     static class CallStack extends SecurityManager JavaDoc {
85         /**
86          * Returns the current execution stack as an array of classes.
87          * The length of the array is the number of methods on the execution
88          * stack. The element at index 0 is the class of the currently executing
89          * method, the element at index 1 is the class of that method's caller,
90          * and so on.
91          *
92          * @return current execution stack as an array of classes.
93          */

94         public Class JavaDoc[] get() {
95             return getClassContext();
96         }
97     }
98
99     /**
100      * The class that we will search for in the call stack
101      * (Avalon logging abstraction)
102      */

103     private final Class JavaDoc logkitClass = LogKitLogger.class;
104
105     /**
106      * The class that we will search for in the call stack
107      * (LogKit logger)
108      */

109     private final Class JavaDoc loggerClass = Logger.class;
110
111     /**
112      * The SecurityManager implementation which gives us access to
113      * the stack frame
114      */

115     private CallStack callStack;
116
117     /**
118      * The depth to which stacktraces are printed out
119      */

120     private final int m_stackDepth;
121
122
123     public CocoonLogFormatter() {
124         this(DEFAULT_STACK_DEPTH);
125     }
126
127     public CocoonLogFormatter(int stackDepth) {
128         try {
129             this.callStack = new CallStack();
130         } catch (SecurityException JavaDoc e) {
131             // Ignore security exception
132
}
133         this.m_stackDepth = stackDepth;
134     }
135
136     protected int getTypeIdFor(String JavaDoc type) {
137         // Search for new patterns defined here, or else delegate
138
// to the parent class
139
if (type.equalsIgnoreCase(TYPE_CLASS_STR)) {
140             return TYPE_CLASS;
141         } else if (type.equalsIgnoreCase(TYPE_URI_STR)) {
142             return TYPE_URI;
143         } else if (type.equalsIgnoreCase(TYPE_THREAD_STR)) {
144             return TYPE_THREAD;
145         } else if (type.equalsIgnoreCase(TYPE_HOST_STR)) {
146             return TYPE_HOST;
147         } else if (type.equalsIgnoreCase(TYPE_QUERY_STR)) {
148             return TYPE_QUERY;
149         } else if (type.equalsIgnoreCase(TYPE_ROOTTHROWABLE_STR)) {
150             return TYPE_ROOTTHROWABLE;
151         } else {
152             return super.getTypeIdFor(type);
153         }
154     }
155
156     protected String JavaDoc formatPatternRun(LogEvent event, PatternRun run) {
157         // Format new patterns defined here, or else delegate to
158
// the parent class
159
switch (run.m_type) {
160             case TYPE_CLASS:
161                 return getClass(run.m_format);
162             case TYPE_URI:
163                 return getURI(event.getContextMap());
164             case TYPE_THREAD:
165                 return getThread(event.getContextMap());
166             case TYPE_HOST:
167                 return getHost(event.getContextMap());
168             case TYPE_QUERY:
169                 return getQueryString(event.getContextMap());
170             case TYPE_ROOTTHROWABLE:
171                 Throwable JavaDoc thr = event.getThrowable();
172                 Throwable JavaDoc root = ExceptionUtils.getRootCause(thr); // Can be null if no cause
173
return getStackTrace(root == null ? thr : root, run.m_format);
174         }
175         return super.formatPatternRun(event, run);
176     }
177
178     /**
179      * Finds the class that has called Logger.
180      */

181     private String JavaDoc getClass(String JavaDoc format) {
182         if (this.callStack != null) {
183             Class JavaDoc[] stack = this.callStack.get();
184
185             // Traverse the call stack in reverse order until we find a Logger
186
for (int i = stack.length - 1; i >= 0; i--) {
187                 if (this.logkitClass.isAssignableFrom(stack[i]) ||
188                     this.loggerClass.isAssignableFrom(stack[i])) {
189                     // Found: the caller is the previous stack element
190
String JavaDoc className = stack[i + 1].getName();
191                     // Handle optional format
192
if (TYPE_CLASS_SHORT_STR.equalsIgnoreCase(format)) {
193                         className = ClassUtils.getShortClassName(className);
194                     }
195                     return className;
196                 }
197             }
198         }
199
200         // No callStack: can occur when running under SecurityManager, or
201
// no logger found in call stack: can occur with AsyncLogTarget
202
// where formatting takes place in a different thread.
203
return "Unknown-Class";
204     }
205
206     /**
207      * Find the URI that is being processed.
208      */

209     private String JavaDoc getURI(ContextMap ctxMap) {
210         // Get URI from the the object model.
211
if (ctxMap != null) {
212             final Object JavaDoc context = ctxMap.get("objectModel");
213             if (context != null && context instanceof Map JavaDoc) {
214                 // Get the request
215
final Request request = ObjectModelHelper.getRequest((Map JavaDoc) context);
216                 if (request != null) {
217                     return request.getRequestURI();
218                 }
219             }
220         }
221
222         return "Unknown-URI";
223     }
224
225     /**
226      * Find request query string
227      */

228     private String JavaDoc getQueryString(ContextMap ctxMap) {
229         if (ctxMap != null) {
230             final Object JavaDoc context = ctxMap.get("objectModel");
231             if (context != null && context instanceof Map JavaDoc) {
232                 // Get the request
233
final Request request = ObjectModelHelper.getRequest((Map JavaDoc) context);
234                 if (request != null) {
235                     final String JavaDoc queryString = request.getQueryString();
236                     if (queryString != null) {
237                         return "?" + queryString;
238                     }
239                 }
240             }
241         }
242         return "";
243     }
244
245     /**
246      * Find the host header of the request that is being processed.
247      */

248     private String JavaDoc getHost(ContextMap ctxMap) {
249         // Get URI from the the object model.
250
if (ctxMap != null) {
251             final Object JavaDoc context = ctxMap.get("objectModel");
252             if (context != null && context instanceof Map JavaDoc) {
253                 // Get the request
254
final Request request = ObjectModelHelper.getRequest((Map JavaDoc) context);
255                 if (request != null) {
256                     return request.getHeader("host");
257                 }
258             }
259         }
260
261         return "Unknown-Host";
262     }
263
264     /**
265      * Find the thread that is logged this event.
266      */

267     private String JavaDoc getThread(ContextMap ctxMap) {
268         // Get thread name from the context.
269
if (ctxMap != null) {
270             final String JavaDoc threadName = (String JavaDoc) ctxMap.get("threadName");
271             if (threadName != null) {
272                 return threadName;
273             }
274         }
275
276         return "Unknown-Thread";
277     }
278
279     /**
280      * Utility method to format stack trace so that CascadingExceptions are
281      * formatted with all nested exceptions.
282      *
283      * <p>FIXME: copied from AvalonFormatter, to be removed if ExtensiblePatternFormatter
284      * replaces PatternFormatter.</p>
285      *
286      * @param throwable the throwable instance
287      * @param format ancilliary format parameter - allowed to be null
288      * @return the formatted string
289      */

290     protected String JavaDoc getStackTrace(final Throwable JavaDoc throwable, final String JavaDoc format) {
291         if (throwable != null) {
292             LocatedException.ensureCauseChainIsSet(throwable);
293             return ExceptionUtils.getStackTrace(throwable);
294             //return ExceptionUtil.printStackTrace(throwable, m_stackDepth);
295
}
296
297         return null;
298     }
299
300     /**
301      * Utility method to format time.
302      *
303      * @param time the time
304      * @param pattern ancilliary pattern parameter - allowed to be null
305      * @return the formatted string
306      */

307     protected String JavaDoc getTime(final long time, String JavaDoc pattern) {
308         if (pattern == null || DEFAULT_TIME_PATTERN.equals(pattern)) {
309             return dateFormatter.format(time);
310         }
311         return FastDateFormat.getInstance(pattern).format(time);
312     }
313 }
314
Popular Tags