KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > logging > Logging


1 /*
2 This software is OSI Certified Open Source Software.
3 OSI Certified is a certification mark of the Open Source Initiative.
4
5 The license (Mozilla version 1.0) can be read at the MMBase site.
6 See http://www.MMBase.org/license
7
8 */

9
10 package org.mmbase.util.logging;
11
12 import java.util.Iterator JavaDoc;
13 import java.lang.reflect.Method JavaDoc;
14
15 import org.mmbase.util.ResourceWatcher;
16 import org.mmbase.util.ResourceLoader;
17 import org.mmbase.util.xml.DocumentReader;
18
19 /**
20  * With this class the logging is configured and it supplies the `Logger' objects.
21  * <p>
22  * For example:
23  * <code>
24  * <pre>
25  * <tt>
26  * <b><font color=#0000FF>import</font></b> org.mmbase.util.logging.Logging;
27  * <b><font color=#0000FF>import</font></b> org.mmbase.util.logging.Logger;
28  * <b><font color=#0000FF>import</font></b> org.mmbase.util.logging.Level;
29  *
30  * <b><font color=#0000FF>public</font></b> <b><font color=#0000FF>class</font></b> test {
31  *
32  * <b><font color=#0000FF>static</font></b> {
33  * Logging.configure(<font color=#FF0000>"log.xml"</font>);
34  * }
35  *
36  * <b><font color=#0000FF>static</font></b> Logger log = Logging.getLoggerInstance(test.<b><font color=#0000FF>class</font></b>.getName());
37  *
38  * <b><font color=#0000FF>public</font></b> <b><font color=#0000FF>static</font></b> <font color=#009900>void</font> main(String[] args) {
39  * log.debug(<font color=#FF0000>"start"</font>);
40  * log.info(<font color=#FF0000>"Entering application."</font>);
41  *
42  * log.setPriority(Level.TRACE);
43  * <b><font color=#0000FF>if</font></b> (log.isDebugEnabled()) {
44  * log.debug(<font color=#FF0000>"debug een"</font>);
45  * log.trace(<font color=#FF0000>"trace twee"</font>);
46  * }
47  * log.info(<font color=#FF0000>"info"</font>);
48  * log.service(<font color=#FF0000>"service"</font>);
49  *
50  *
51  * Logging.shutdown();
52  * }
53  * }
54  * </tt>
55  * </pre>
56  * </code>
57  * </p>
58  *
59  * @author Michiel Meeuwissen
60  * @version $Id: Logging.java,v 1.40 2006/07/15 19:51:45 michiel Exp $
61  */

62
63
64 public class Logging {
65
66     private static Class JavaDoc logClass = SimpleTimeStampImpl.class; // default Logger Implementation
67
private static boolean configured = false;
68     private static final Logger log = getLoggerInstance(Logging.class); // logger for this class itself
69

70    /**
71     * The category for logging info about pages (like stop / start). Also if pages take the
72      * initiative for logging themselves they should log below this category.
73      * @since MMBase-1.7
74      */

75     public final static String JavaDoc PAGE_CATEGORY = "org.mmbase.PAGE";
76
77     private static ResourceLoader resourceLoader;
78
79     /**
80      * @since MMBase-1.8
81      */

82     private static ResourceWatcher configWatcher;
83
84     private static String JavaDoc machineName = "localhost";
85
86
87     private Logging() {
88         // this class has no instances.
89
}
90
91
92     /**
93      * @since MMBase-1.8
94      */

95     public static String JavaDoc getMachineName() {
96         return machineName;
97     }
98     /**
99      * @since MMBase-1.8
100      */

101     public static void setMachineName(String JavaDoc mn) {
102         machineName = mn;
103     }
104
105
106     /**
107      * Configure the logging system.
108      *
109      * @param configFile Path to an xml-file in which is described
110      * which class must be used for logging, and how this will be
111      * configured (typically the name of another configuration file).
112      *
113      */

114
115     public static void configure (ResourceLoader rl, String JavaDoc configFile) {
116         resourceLoader = rl;
117         configWatcher = new ResourceWatcher(rl) {
118             public void onChange(String JavaDoc s) {
119                 configure(resourceLoader, s);
120             }
121         };
122
123         if (configFile == null) {
124             log.info("No configfile given, default configuration will be used.");
125             return;
126         }
127
128        // There is a problem when dtd's for the various modules are on a remote
129
// machine and this machine is down. Log4j will hang without an error and if
130
// SimpleImpl is used in log.xml it too will constantly try to connect to the
131
// machine for the dtd's without giving an error! This line might give a hint
132
// where to search for these kinds of problems..
133

134         log.info("Configuring logging with " + configFile);
135         ///System.out.println("(If logging does not start then dtd validation might be a problem on your server)");
136

137         configWatcher.add(configFile);
138         configWatcher.setDelay(10 * 1000); // check every 10 secs if config changed
139
configWatcher.start();
140
141         DocumentReader reader;
142         try {
143             reader = new DocumentReader(resourceLoader.getInputSource(configFile), Logging.class);
144         } catch (Exception JavaDoc e) {
145             log.error("Could not open " + configFile + " " + e, e);
146             return;
147         }
148         if (reader == null) {
149             log.error("No " + configFile);
150             return;
151         }
152
153         String JavaDoc classToUse = SimpleImpl.class.getName(); // default
154
String JavaDoc configuration = "stderr,info"; // default
155
try { // to read the XML configuration file
156
String JavaDoc claz = reader.getElementValue("logging.class");
157             if (claz != null) {
158                 classToUse = claz;
159             }
160             String JavaDoc config = reader.getElementValue("logging.configuration");
161             if (config != null) configuration = config;
162         } catch (Exception JavaDoc e) {
163             log.error("Exception during parsing: " + e);
164             log.error(stackTrace(e));
165         }
166
167
168         log.info("Class to use for logging " + classToUse);
169         // System.out.println("(Depending on your selected logging system no more logging");
170
// System.out.println("might be written to this file. See the configuration of the");
171
// System.out.println("selected logging system for more hints where logging will appear)");
172
Class JavaDoc logClassCopy = logClass; // if something's wrong, we can restore the current value.
173
try { // to find the configured class
174
logClass = Class.forName(classToUse);
175             if (configured) {
176                 if (! logClassCopy.equals(logClass)) {
177                     log.warn("Tried to change logging implementation from " + logClassCopy + " to " + logClass + ". This is not really possible (most static instances are unreachable). Trying anyway as requested, if this gives strange results, you might need to restart.");
178                 }
179             }
180
181         } catch (ClassNotFoundException JavaDoc e) {
182             log.error("Could not find class " + classToUse);
183             log.error(e.toString());
184             logClass = logClassCopy;
185         } catch (Throwable JavaDoc e) {
186             log.error("Exception to find class " + classToUse + ": " + e);
187             log.info("Falling back to " + logClassCopy.getName());
188             logClass = logClassCopy;
189         }
190         // System.out.println("logging to " + getLocations());
191
configureClass(configuration);
192         configured = true;
193         log.service("Logging configured");
194         log.debug("Now watching " + configWatcher.getResources());
195         log.debug("Replacing wrappers " + LoggerWrapper.getWrappers());
196         Iterator JavaDoc wrappers = LoggerWrapper.getWrappers().iterator();
197         while (wrappers.hasNext()) {
198             LoggerWrapper wrapper = (LoggerWrapper) wrappers.next();
199             wrapper.setLogger(getLoggerInstance(wrapper.getName()));
200             log.debug("Replaced logger " + wrapper.getName());
201         }
202     }
203
204     /**
205      * Calls the 'configure' static method of the used logging class,
206      * or does nothing if it doesn't exist. You could call this method
207      * if you want to avoid using 'configure', which parses an XML file.
208      **/

209
210     public static void configureClass(String JavaDoc configuration) {
211         try { // to configure
212
// System.out.println("Found class " + logClass.getName());
213
Method JavaDoc conf = logClass.getMethod("configure", new Class JavaDoc[] { String JavaDoc.class } );
214             conf.invoke(null, new Object JavaDoc[] { configuration } );
215         } catch (NoSuchMethodException JavaDoc e) {
216             log.debug("Could not find configure method in " + logClass.getName());
217             // okay, simply don't configure
218
} catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
219             log.error("Invocation Exception while configuration class. " + e.getMessage(), e);
220         } catch (Exception JavaDoc e) {
221             log.error("", e);
222         }
223     }
224
225     /**
226      * Logging is configured with a log file. This method returns the File which was used.
227      */

228     public static ResourceLoader getResourceLoader() {
229         return resourceLoader;
230     }
231
232     /**
233      * After configuring the logging system, you can get Logger instances to log with.
234      *
235      * @param s A string describing the `category' of the Logger. This is a log4j concept.
236      */

237
238     public static Logger getLoggerInstance (String JavaDoc s) {
239         // call the getLoggerInstance static method of the logclass:
240
try {
241             Method JavaDoc getIns = logClass.getMethod("getLoggerInstance", new Class JavaDoc[] { String JavaDoc.class } );
242             Logger logger = (Logger) getIns.invoke(null, new Object JavaDoc[] {s});
243             if (configured) {
244                 return logger;
245             } else {
246                 return new LoggerWrapper(logger, s);
247             }
248         } catch (Exception JavaDoc e) {
249             log.warn(e);
250             return SimpleImpl.getLoggerInstance(s);
251         }
252     }
253
254     /**
255      * Most Logger categories in MMBase are based on class name.
256      * @since MMBase-1.6.4
257      */

258     public static Logger getLoggerInstance(Class JavaDoc cl) {
259         return getLoggerInstance(cl.getName());
260     }
261
262     /**
263      * Returns a Set of String which indicates where your logging can
264      * be (If this is implemented in the class).
265      */

266     /*
267     public static Set getLocations() {
268         // call the getLoggerInstance static method of the logclass:
269         try {
270             Method getIns = logClass.getMethod("getLocations", new Class[] {} );
271             return (Set) getIns.invoke(null, new Object[] {});
272         } catch (Exception e) {
273             HashSet result = new HashSet();
274             result.add("<could not be determined>");
275             return result;
276         }
277     }
278     */

279
280     /**
281      * If the configured Logger implements a shutdown static method,
282      * it will be called. (the log4j Category does).
283      *
284      */

285     public static void shutdown() {
286         try {
287             if (logClass != null) {
288                 Method JavaDoc shutdown = logClass.getMethod("shutdown", new Class JavaDoc[] {} );
289                 shutdown.invoke(null, new Object JavaDoc[] {} );
290             }
291         } catch (NoSuchMethodException JavaDoc e) {
292             // System.err.println("No such method"); // okay, nothing to shutdown.
293
} catch (Exception JavaDoc e) {
294             System.err.println(e + stackTrace(e));
295         }
296
297     }
298
299     /**
300      * Returns the stacktrace of the current call. This can be used to get a stacktrace
301      * when no exception was thrown and my help determine the root cause of an error message
302      * (what class called the method that gave the error message.
303      * @since MMBase-1.7
304      *
305      **/

306     public static String JavaDoc stackTrace() {
307         return stackTrace(-1);
308     }
309
310     /**
311      * @since MMBase-1.7
312      */

313     public static String JavaDoc stackTrace(int max) {
314         Exception JavaDoc e = new Exception JavaDoc("logging.stacktrace");
315         /*
316         StackTraceElement[] stack = e.getStackTrace();
317         java.util.List stackList = new java.util.ArrayList(java.util.Arrays.asList(stack));
318         stackList.remove(0); // is Logging.stackTrace, which is hardly interesting
319         e.setStackTrace((StackTraceElement[])stackList.toArray());
320         */

321         return stackTrace(e, max);
322     }
323
324     /**
325      * Returns the stacktrace of an exception as a string, which can
326      * be logged handy. Doing simply e.printStackTrace() would dump
327      * the stack trace to standard error, which with the log4j
328      * implementation will appear in the log file too, but this is a
329      * little nicer.
330      *
331      * It is also possible to call 'error' or 'fatal' with an extra argument.
332      *
333      * @param e the Throwable from which the stack trace must be stringified.
334      *
335      **/

336     public static String JavaDoc stackTrace(Throwable JavaDoc e) {
337         return stackTrace(e, -1);
338     }
339
340     /**
341      * Also returns a stringified stack trace to log, but no deeper than given max.
342      * @since MMBase-1.7
343      */

344     public static String JavaDoc stackTrace(Throwable JavaDoc e, int max) {
345         StackTraceElement JavaDoc[] stackTrace = e.getStackTrace();
346         String JavaDoc message = e.getMessage();
347         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(e.getClass().getName() + ": ");
348         if (message == null) {
349
350         } else {
351             buf.append(message);
352         }
353         for (int i = 0; i < stackTrace.length; i++) {
354             if (i == max) break;
355             buf.append("\n at ").append(stackTrace[i]);
356         }
357         Throwable JavaDoc t = e.getCause();
358         if (t != null) {
359             buf.append(stackTrace(t, max));
360         }
361         return buf.toString();
362     }
363
364     /**
365      * @since MMBase-1.8
366      */

367     public static String JavaDoc applicationStacktrace() {
368         Exception JavaDoc e = new Exception JavaDoc("logging.showApplicationStacktrace");
369         return applicationStacktrace(e);
370     }
371
372     /**
373      * @since MMBase-1.8
374      */

375     public static String JavaDoc applicationStacktrace(Throwable JavaDoc e) {
376         StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Application stacktrace");
377
378         // Get the stack trace
379
StackTraceElement JavaDoc stackTrace[] = e.getStackTrace();
380         // stackTrace[0] contains the method that created the exception.
381
// stackTrace[stackTrace.length-1] contains the oldest method call.
382
// Enumerate each stack element.
383

384         boolean mmbaseClassesFound = false;
385         int appended = 0;
386         for (int i = 0; i < stackTrace.length; i++) {
387            String JavaDoc className = stackTrace[i].getClassName();
388
389            if (className.indexOf("org.mmbase") > -1) {
390                mmbaseClassesFound = true;
391                // show mmbase taglib
392
if (className.indexOf("bridge.jsp.taglib") > -1) {
393                    buf.append("\n at ").append(stackTrace[i]);
394                    appended++;
395                }
396            } else {
397                if (mmbaseClassesFound) {
398                    // show none mmbase method which invoked an mmbase method.
399
buf.append("\n at ").append(stackTrace[i]);
400                    appended++;
401                    break;
402                }
403                // show compiled jsp lines
404
if (className.indexOf("_jsp") > -1) {
405                    buf.append("\n at ").append(stackTrace[i]);
406                    appended++;
407                }
408            }
409         }
410         if (appended == 0) {
411             for (int i = 2; i < stackTrace.length; i++) {
412                 buf.append("\n at ").append(stackTrace[i]);
413             }
414         }
415         return buf.toString();
416     }
417
418 }
419
Popular Tags