KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > logging > log4j > Log4jImpl


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.log4j;
11
12 import org.mmbase.util.logging.Logger;
13 import org.mmbase.util.logging.Level;
14 import org.mmbase.util.logging.Logging;
15
16 import org.mmbase.util.ResourceWatcher;
17 import org.mmbase.util.ResourceLoader;
18
19 import org.apache.log4j.xml.DOMConfigurator;
20
21 import java.io.*;
22
23 import java.io.PrintStream JavaDoc;
24 import java.io.File JavaDoc;
25
26 /**
27  * This Logger implementation extends the Logger class from the log4j
28  * project (version >= 1.2). It has the following extra functionality.
29  *
30  * First of all it uses the LoggerLevel class for Level, and so
31  * has two extra priorities, namely 'trace' and 'service'.
32  *
33  * Further it instantiates one object of itself, named `STDERR' to
34  * which stderr will be redirected. Normally this will happen with
35  * priority `info' but Exceptions will get priorty `fatal'.
36  *
37  * It also has a static member method `configure', which calls the
38  * configure of DOMConfigurator, in this way log4j classes are used
39  * only here, and the rest of MMBase can use only `Logger'.
40  *
41  * @author Michiel Meeuwissen
42  */

43
44 public final class Log4jImpl extends org.apache.log4j.Logger implements Logger {
45     // class is final, perhaps then its methods can be inlined when compiled with -O?
46

47     // It's enough to instantiate a factory once and for all.
48
private final static org.apache.log4j.spi.LoggerRepository repository = new LoggerRepository(getRootLogger());
49     private static Logger log = Logging.getLoggerInstance(Log4jImpl.class);
50
51     private static final String JavaDoc classname = Log4jImpl.class.getName();
52
53     private static ResourceWatcher configWatcher;
54
55     /**
56      * Constructor, like the constructor of {@link org.apache.log4j.Logger}.
57      */

58     protected Log4jImpl(String JavaDoc name) {
59         super(name);
60     }
61
62     /**
63      * As getLogger, but cast to MMBase Logger already. And the possible
64      * ClassCastException is caught.
65      */

66     public static Log4jImpl getLoggerInstance(String JavaDoc name) {
67         try {
68             return (Log4jImpl) repository.getLogger(name);
69         } catch (ClassCastException JavaDoc e) {
70             Log4jImpl root = (Log4jImpl) getRootLogger(); // make it log on root, and log a huge error, that something is wrong.
71
root.error("ClassCastException, probably you've forgotten a class attribute in your configuration file. It must say class=\"" + Log4jImpl.class.getName() + "\"");
72             return root;
73         }
74     }
75
76
77     /**
78      * Calls the configure method of DOMConfigurator, and redirect
79      * standard error to STDERR category. It also starts up the
80      * FileWatcher. The 'configureAndWatch' method of DOMConfigurator
81      * used to be used, but it is not feasible anymore because
82      * 1. cannot give the repository then. 2. Cannot log the happening
83      * on normal way.
84      *
85      * @param s A string to the xml-configuration file. Can be
86      * absolute, or relative to the Logging configuration file.
87      **/

88
89     public static void configure(String JavaDoc s) {
90
91         log.info("logging configurationfile : " + s);
92
93         ResourceLoader rl = Logging.getResourceLoader();
94
95         log.info("using " + rl + " for resolving " + s);
96         configWatcher = new ResourceWatcher (rl) {
97                 public void onChange(String JavaDoc s) {
98                 doConfigure(resourceLoader.getResourceAsStream(s));
99             }
100         };
101
102         configWatcher.clear();
103         configWatcher.add(s);
104
105         doConfigure(rl.getResourceAsStream(s));
106
107         configWatcher.setDelay(10 * 1000); // check every 10 secs if config changed
108
configWatcher.start();
109         log = getLoggerInstance(Log4jImpl.class.getName());
110
111         Log4jImpl err = getLoggerInstance("STDERR");
112         // a trick: if the level of STDERR is FATAL, then stderr will not be captured at all.
113
if(err.getLevel() != Log4jLevel.FATAL) {
114             log.service("Redirecting stderr to MMBase logging (If you don't like this, then put the STDER logger to 'fatal')");
115             System.setErr(new LoggerStream(err));
116         }
117     }
118
119     protected static void doConfigure(InputStream i) {
120         DOMConfigurator domConfigurator = new DOMConfigurator();
121         domConfigurator.doConfigure(i, repository);
122     }
123     /**
124      * Performs the actual parsing of the log4j configuration file and handles the errors
125      */

126     protected static void doConfigure(File JavaDoc f) {
127         log.info("Parsing " + f.getAbsolutePath());
128         try {
129             doConfigure(new FileInputStream(f));
130         } catch (java.io.FileNotFoundException JavaDoc e) {
131             log.error("Could not find " + f + " to configure logging: " + e.toString());
132         }
133
134     }
135
136     public void setLevel(Level p) {
137         switch (p.toInt()) {
138         case Level.TRACE_INT: setLevel(Log4jLevel.TRACE); break;
139         case Level.DEBUG_INT: setLevel(Log4jLevel.DEBUG); break;
140         case Level.SERVICE_INT: setLevel(Log4jLevel.SERVICE); break;
141         case Level.INFO_INT: setLevel(Log4jLevel.INFO); break;
142         case Level.WARN_INT: setLevel(Log4jLevel.WARN); break;
143         case Level.ERROR_INT: setLevel(Log4jLevel.ERROR); break;
144         case Level.FATAL_INT: setLevel(Log4jLevel.FATAL); break;
145         case Level.OFF_INT: setLevel(Log4jLevel.OFF); break;
146         default: break;
147         }
148     }
149
150     /**
151      * This method overrides {@link org.apache.log4j.Logger#getInstance} by supplying
152      * its own factory type as a parameter.
153      */

154     public static org.apache.log4j.Category getInstance(String JavaDoc name) {
155         return getLogger(name);
156     }
157
158     public static org.apache.log4j.Logger getLogger(String JavaDoc name) {
159         return repository.getLogger(name);
160     }
161
162     /**
163      * A new logging method that takes the TRACE priority.
164      */

165     public final void trace(Object JavaDoc message) {
166         // disable is defined in Category
167
if (repository.isDisabled(Log4jLevel.TRACE_INT)) {
168             return;
169         }
170         if (Log4jLevel.TRACE.isGreaterOrEqual(this.getEffectiveLevel()))
171             //callAppenders(new LoggingEvent(classname, this, Log4jLevel.TRACE, message, null));
172
forcedLog(classname, Log4jLevel.TRACE, message, null);
173     }
174
175     public final void trace(Object JavaDoc message, Throwable JavaDoc t) {
176         // disable is defined in Category
177
if (repository.isDisabled(Log4jLevel.TRACE_INT)) {
178             return;
179         }
180         if (Log4jLevel.TRACE.isGreaterOrEqual(this.getEffectiveLevel()))
181             //callAppenders(new LoggingEvent(classname, this, Log4jLevel.TRACE, message, null));
182
forcedLog(classname, Log4jLevel.TRACE, message, t);
183     }
184
185     /**
186      * A new logging method that takes the SERVICE priority.
187      */

188     public final void service(Object JavaDoc message) {
189         // disable is defined in Category
190
if (repository.isDisabled(Log4jLevel.SERVICE_INT)) {
191             return;
192         }
193         if (Log4jLevel.SERVICE.isGreaterOrEqual(this.getEffectiveLevel()))
194             //callAppenders(new LoggingEvent(classname, this, Log4jLevel.SERVICE, message, null));
195
forcedLog(classname, Log4jLevel.SERVICE, message, null);
196     }
197
198     public final void service(Object JavaDoc message, Throwable JavaDoc t) {
199         // disable is defined in Category
200
if (repository.isDisabled(Log4jLevel.SERVICE_INT)) {
201             return;
202         }
203         if (Log4jLevel.SERVICE.isGreaterOrEqual(this.getEffectiveLevel()))
204             //callAppenders(new LoggingEvent(classname, this, Log4jLevel.SERVICE, message, null));
205
forcedLog(classname, Log4jLevel.SERVICE, message, t);
206     }
207
208     public final boolean isServiceEnabled() {
209         if(repository.isDisabled( Log4jLevel.SERVICE_INT))
210             return false;
211         return Log4jLevel.SERVICE.isGreaterOrEqual(this.getEffectiveLevel());
212     }
213
214     public final boolean isTraceEnabled() {
215         if(repository.isDisabled( Log4jLevel.TRACE_INT))
216             return false;
217         return Log4jLevel.TRACE.isGreaterOrEqual(this.getEffectiveLevel());
218     }
219     
220     public static void shutdown() {
221         Log4jImpl err = getLoggerInstance("STDERR");
222         if(err.getLevel() != Log4jLevel.FATAL) {
223             log.service("System stderr now going to stdout");
224             System.setErr(System.out);
225         }
226         log.service("Shutting down log4j");
227         repository.shutdown();
228     }
229
230     /**
231      * Catches stderr and sends it also to the log file (with category `stderr').
232      *
233      * In this way, things producing standard output, such as uncatch
234      * exceptions, will at least appear in the log-file.
235      *
236      **/

237
238     private static class LoggerStream extends PrintStream JavaDoc {
239
240         private Logger log;
241
242         private int checkCount = 0; // needed to avoid infinite
243
// recursion in some errorneos situations.
244

245         LoggerStream (Log4jImpl l) throws IllegalArgumentException JavaDoc {
246             super(System.out);
247             if (l == null) {
248                 throw new IllegalArgumentException JavaDoc("logger == null");
249             }
250             log = l;
251         }
252
253         private LoggerStream () {
254             // do not use.
255
super(System.out);
256         }
257         // simply overriding all methods that possibly could be used (forgotten some still)
258
public void print (char[] s) { log.warn(new String JavaDoc(s)); }
259         public void print (String JavaDoc s) { log.warn(s); }
260         public void print (Object JavaDoc s) { log.warn(s.toString()); }
261         public void println (char[] s) { log.warn(new String JavaDoc(s)); }
262         public void println (String JavaDoc s) {
263             // if something goes wrong log4j write to standard error
264
// we don't want to go in an infinite loop then, if LoggerStream is stderr too.
265
if (checkCount > 0) {
266                 System.out.println(s);
267             } else {
268                 checkCount++;
269                 log.trace("6"); log.warn(s);
270                 checkCount--;
271             }
272         }
273         public void println (Object JavaDoc s) {
274             // it seems that exception are written to log in this way, so we can check
275
// if s is an exception, in which case we want to log with FATAL.
276
if (Exception JavaDoc.class.isAssignableFrom(s.getClass())) {
277                 log.fatal(s.toString()); // uncaught exception, that's a fatal error
278
} else {
279                 log.warn(s.toString());
280             }
281         }
282
283     }
284
285 }
286
287
Popular Tags