1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.logging.impl;
19
20 import java.io.InputStream;
21 import java.io.Serializable;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26 import java.text.DateFormat;
27 import java.text.SimpleDateFormat;
28 import java.util.Date;
29 import java.util.Properties;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogConfigurationException;
33
34 /***
35 * <p>Simple implementation of Log that sends all enabled log messages,
36 * for all defined loggers, to System.err. The following system properties
37 * are supported to configure the behavior of this logger:</p>
38 * <ul>
39 * <li><code>org.apache.commons.logging.simplelog.defaultlog</code> -
40 * Default logging detail level for all instances of SimpleLog.
41 * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
42 * If not specified, defaults to "info". </li>
43 * <li><code>org.apache.commons.logging.simplelog.log.xxxxx</code> -
44 * Logging detail level for a SimpleLog instance named "xxxxx".
45 * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
46 * If not specified, the default logging detail level is used.</li>
47 * <li><code>org.apache.commons.logging.simplelog.showlogname</code> -
48 * Set to <code>true</code> if you want the Log instance name to be
49 * included in output messages. Defaults to <code>false</code>.</li>
50 * <li><code>org.apache.commons.logging.simplelog.showShortLogname</code> -
51 * Set to <code>true</code> if you want the last component of the name to be
52 * included in output messages. Defaults to <code>true</code>.</li>
53 * <li><code>org.apache.commons.logging.simplelog.showdatetime</code> -
54 * Set to <code>true</code> if you want the current date and time
55 * to be included in output messages. Default is <code>false</code>.</li>
56 * <li><code>org.apache.commons.logging.simplelog.dateTimeFormat</code> -
57 * The date and time format to be used in the output messages.
58 * The pattern describing the date and time format is the same that is
59 * used in <code>java.text.SimpleDateFormat</code>. If the format is not
60 * specified or is invalid, the default format is used.
61 * The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li>
62 * </ul>
63 *
64 * <p>In addition to looking for system properties with the names specified
65 * above, this implementation also checks for a class loader resource named
66 * <code>"simplelog.properties"</code>, and includes any matching definitions
67 * from this resource (if it exists).</p>
68 *
69 * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
70 * @author Rod Waldhoff
71 * @author Robert Burrell Donkin
72 *
73 * @version $Id: SimpleLog.java,v 1.21 2004/06/06 20:47:56 rdonkin Exp $
74 */
75 public class SimpleLog implements Log, Serializable {
76
77
78
79
80 /*** All system properties used by <code>SimpleLog</code> start with this */
81 static protected final String systemPrefix =
82 "org.apache.commons.logging.simplelog.";
83
84 /*** Properties loaded from simplelog.properties */
85 static protected final Properties simpleLogProps = new Properties();
86
87 /*** The default format to use when formating dates */
88 static protected final String DEFAULT_DATE_TIME_FORMAT =
89 "yyyy/MM/dd HH:mm:ss:SSS zzz";
90
91 /*** Include the instance name in the log message? */
92 static protected boolean showLogName = false;
93 /*** Include the short name ( last component ) of the logger in the log
94 * message. Defaults to true - otherwise we'll be lost in a flood of
95 * messages without knowing who sends them.
96 */
97 static protected boolean showShortName = true;
98 /*** Include the current time in the log message */
99 static protected boolean showDateTime = false;
100 /*** The date and time format to use in the log message */
101 static protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
102 /*** Used to format times */
103 static protected DateFormat dateFormatter = null;
104
105
106
107
108 /*** "Trace" level logging. */
109 public static final int LOG_LEVEL_TRACE = 1;
110 /*** "Debug" level logging. */
111 public static final int LOG_LEVEL_DEBUG = 2;
112 /*** "Info" level logging. */
113 public static final int LOG_LEVEL_INFO = 3;
114 /*** "Warn" level logging. */
115 public static final int LOG_LEVEL_WARN = 4;
116 /*** "Error" level logging. */
117 public static final int LOG_LEVEL_ERROR = 5;
118 /*** "Fatal" level logging. */
119 public static final int LOG_LEVEL_FATAL = 6;
120
121 /*** Enable all logging levels */
122 public static final int LOG_LEVEL_ALL = (LOG_LEVEL_TRACE - 1);
123
124 /*** Enable no logging levels */
125 public static final int LOG_LEVEL_OFF = (LOG_LEVEL_FATAL + 1);
126
127
128
129 private static String getStringProperty(String name) {
130 String prop = null;
131 try {
132 prop = System.getProperty(name);
133 } catch (SecurityException e) {
134 ;
135 }
136 return (prop == null) ? simpleLogProps.getProperty(name) : prop;
137 }
138
139 private static String getStringProperty(String name, String dephault) {
140 String prop = getStringProperty(name);
141 return (prop == null) ? dephault : prop;
142 }
143
144 private static boolean getBooleanProperty(String name, boolean dephault) {
145 String prop = getStringProperty(name);
146 return (prop == null) ? dephault : "true".equalsIgnoreCase(prop);
147 }
148
149
150
151
152 static {
153
154 InputStream in = getResourceAsStream("simplelog.properties");
155 if(null != in) {
156 try {
157 simpleLogProps.load(in);
158 in.close();
159 } catch(java.io.IOException e) {
160
161 }
162 }
163
164 showLogName = getBooleanProperty( systemPrefix + "showlogname", showLogName);
165 showShortName = getBooleanProperty( systemPrefix + "showShortLogname", showShortName);
166 showDateTime = getBooleanProperty( systemPrefix + "showdatetime", showDateTime);
167
168 if(showDateTime) {
169 dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat",
170 dateTimeFormat);
171 try {
172 dateFormatter = new SimpleDateFormat(dateTimeFormat);
173 } catch(IllegalArgumentException e) {
174
175 dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
176 dateFormatter = new SimpleDateFormat(dateTimeFormat);
177 }
178 }
179 }
180
181
182
183
184 /*** The name of this simple log instance */
185 protected String logName = null;
186 /*** The current log level */
187 protected int currentLogLevel;
188 /*** The short name of this simple log instance */
189 private String shortLogName = null;
190
191
192
193
194 /***
195 * Construct a simple log with given name.
196 *
197 * @param name log name
198 */
199 public SimpleLog(String name) {
200
201 logName = name;
202
203
204
205
206 setLevel(SimpleLog.LOG_LEVEL_INFO);
207
208
209 String lvl = getStringProperty(systemPrefix + "log." + logName);
210 int i = String.valueOf(name).lastIndexOf(".");
211 while(null == lvl && i > -1) {
212 name = name.substring(0,i);
213 lvl = getStringProperty(systemPrefix + "log." + name);
214 i = String.valueOf(name).lastIndexOf(".");
215 }
216
217 if(null == lvl) {
218 lvl = getStringProperty(systemPrefix + "defaultlog");
219 }
220
221 if("all".equalsIgnoreCase(lvl)) {
222 setLevel(SimpleLog.LOG_LEVEL_ALL);
223 } else if("trace".equalsIgnoreCase(lvl)) {
224 setLevel(SimpleLog.LOG_LEVEL_TRACE);
225 } else if("debug".equalsIgnoreCase(lvl)) {
226 setLevel(SimpleLog.LOG_LEVEL_DEBUG);
227 } else if("info".equalsIgnoreCase(lvl)) {
228 setLevel(SimpleLog.LOG_LEVEL_INFO);
229 } else if("warn".equalsIgnoreCase(lvl)) {
230 setLevel(SimpleLog.LOG_LEVEL_WARN);
231 } else if("error".equalsIgnoreCase(lvl)) {
232 setLevel(SimpleLog.LOG_LEVEL_ERROR);
233 } else if("fatal".equalsIgnoreCase(lvl)) {
234 setLevel(SimpleLog.LOG_LEVEL_FATAL);
235 } else if("off".equalsIgnoreCase(lvl)) {
236 setLevel(SimpleLog.LOG_LEVEL_OFF);
237 }
238
239 }
240
241
242
243
244 /***
245 * <p> Set logging level. </p>
246 *
247 * @param currentLogLevel new logging level
248 */
249 public void setLevel(int currentLogLevel) {
250
251 this.currentLogLevel = currentLogLevel;
252
253 }
254
255
256 /***
257 * <p> Get logging level. </p>
258 */
259 public int getLevel() {
260
261 return currentLogLevel;
262 }
263
264
265
266
267
268 /***
269 * <p> Do the actual logging.
270 * This method assembles the message
271 * and then calls <code>write()</code> to cause it to be written.</p>
272 *
273 * @param type One of the LOG_LEVEL_XXX constants defining the log level
274 * @param message The message itself (typically a String)
275 * @param t The exception whose stack trace should be logged
276 */
277 protected void log(int type, Object message, Throwable t) {
278
279 StringBuffer buf = new StringBuffer();
280
281
282 if(showDateTime) {
283 buf.append(dateFormatter.format(new Date()));
284 buf.append(" ");
285 }
286
287
288 switch(type) {
289 case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break;
290 case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break;
291 case SimpleLog.LOG_LEVEL_INFO: buf.append("[INFO] "); break;
292 case SimpleLog.LOG_LEVEL_WARN: buf.append("[WARN] "); break;
293 case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break;
294 case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break;
295 }
296
297
298 if( showShortName) {
299 if( shortLogName==null ) {
300
301 shortLogName = logName.substring(logName.lastIndexOf(".") + 1);
302 shortLogName =
303 shortLogName.substring(shortLogName.lastIndexOf("/") + 1);
304 }
305 buf.append(String.valueOf(shortLogName)).append(" - ");
306 } else if(showLogName) {
307 buf.append(String.valueOf(logName)).append(" - ");
308 }
309
310
311 buf.append(String.valueOf(message));
312
313
314 if(t != null) {
315 buf.append(" <");
316 buf.append(t.toString());
317 buf.append(">");
318
319 java.io.StringWriter sw= new java.io.StringWriter(1024);
320 java.io.PrintWriter pw= new java.io.PrintWriter(sw);
321 t.printStackTrace(pw);
322 pw.close();
323 buf.append(sw.toString());
324 }
325
326
327 write(buf);
328
329 }
330
331
332 /***
333 * <p>Write the content of the message accumulated in the specified
334 * <code>StringBuffer</code> to the appropriate output destination. The
335 * default implementation writes to <code>System.err</code>.</p>
336 *
337 * @param buffer A <code>StringBuffer</code> containing the accumulated
338 * text to be logged
339 */
340 protected void write(StringBuffer buffer) {
341
342 System.err.println(buffer.toString());
343
344 }
345
346
347 /***
348 * Is the given log level currently enabled?
349 *
350 * @param logLevel is this level enabled?
351 */
352 protected boolean isLevelEnabled(int logLevel) {
353
354
355 return (logLevel >= currentLogLevel);
356 }
357
358
359
360
361
362 /***
363 * <p> Log a message with debug log level.</p>
364 */
365 public final void debug(Object message) {
366
367 if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
368 log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
369 }
370 }
371
372
373 /***
374 * <p> Log an error with debug log level.</p>
375 */
376 public final void debug(Object message, Throwable t) {
377
378 if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
379 log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
380 }
381 }
382
383
384 /***
385 * <p> Log a message with trace log level.</p>
386 */
387 public final void trace(Object message) {
388
389 if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
390 log(SimpleLog.LOG_LEVEL_TRACE, message, null);
391 }
392 }
393
394
395 /***
396 * <p> Log an error with trace log level.</p>
397 */
398 public final void trace(Object message, Throwable t) {
399
400 if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
401 log(SimpleLog.LOG_LEVEL_TRACE, message, t);
402 }
403 }
404
405
406 /***
407 * <p> Log a message with info log level.</p>
408 */
409 public final void info(Object message) {
410
411 if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
412 log(SimpleLog.LOG_LEVEL_INFO,message,null);
413 }
414 }
415
416
417 /***
418 * <p> Log an error with info log level.</p>
419 */
420 public final void info(Object message, Throwable t) {
421
422 if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
423 log(SimpleLog.LOG_LEVEL_INFO, message, t);
424 }
425 }
426
427
428 /***
429 * <p> Log a message with warn log level.</p>
430 */
431 public final void warn(Object message) {
432
433 if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
434 log(SimpleLog.LOG_LEVEL_WARN, message, null);
435 }
436 }
437
438
439 /***
440 * <p> Log an error with warn log level.</p>
441 */
442 public final void warn(Object message, Throwable t) {
443
444 if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
445 log(SimpleLog.LOG_LEVEL_WARN, message, t);
446 }
447 }
448
449
450 /***
451 * <p> Log a message with error log level.</p>
452 */
453 public final void error(Object message) {
454
455 if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
456 log(SimpleLog.LOG_LEVEL_ERROR, message, null);
457 }
458 }
459
460
461 /***
462 * <p> Log an error with error log level.</p>
463 */
464 public final void error(Object message, Throwable t) {
465
466 if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
467 log(SimpleLog.LOG_LEVEL_ERROR, message, t);
468 }
469 }
470
471
472 /***
473 * <p> Log a message with fatal log level.</p>
474 */
475 public final void fatal(Object message) {
476
477 if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
478 log(SimpleLog.LOG_LEVEL_FATAL, message, null);
479 }
480 }
481
482
483 /***
484 * <p> Log an error with fatal log level.</p>
485 */
486 public final void fatal(Object message, Throwable t) {
487
488 if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
489 log(SimpleLog.LOG_LEVEL_FATAL, message, t);
490 }
491 }
492
493
494 /***
495 * <p> Are debug messages currently enabled? </p>
496 *
497 * <p> This allows expensive operations such as <code>String</code>
498 * concatenation to be avoided when the message will be ignored by the
499 * logger. </p>
500 */
501 public final boolean isDebugEnabled() {
502
503 return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
504 }
505
506
507 /***
508 * <p> Are error messages currently enabled? </p>
509 *
510 * <p> This allows expensive operations such as <code>String</code>
511 * concatenation to be avoided when the message will be ignored by the
512 * logger. </p>
513 */
514 public final boolean isErrorEnabled() {
515
516 return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
517 }
518
519
520 /***
521 * <p> Are fatal messages currently enabled? </p>
522 *
523 * <p> This allows expensive operations such as <code>String</code>
524 * concatenation to be avoided when the message will be ignored by the
525 * logger. </p>
526 */
527 public final boolean isFatalEnabled() {
528
529 return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
530 }
531
532
533 /***
534 * <p> Are info messages currently enabled? </p>
535 *
536 * <p> This allows expensive operations such as <code>String</code>
537 * concatenation to be avoided when the message will be ignored by the
538 * logger. </p>
539 */
540 public final boolean isInfoEnabled() {
541
542 return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
543 }
544
545
546 /***
547 * <p> Are trace messages currently enabled? </p>
548 *
549 * <p> This allows expensive operations such as <code>String</code>
550 * concatenation to be avoided when the message will be ignored by the
551 * logger. </p>
552 */
553 public final boolean isTraceEnabled() {
554
555 return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
556 }
557
558
559 /***
560 * <p> Are warn messages currently enabled? </p>
561 *
562 * <p> This allows expensive operations such as <code>String</code>
563 * concatenation to be avoided when the message will be ignored by the
564 * logger. </p>
565 */
566 public final boolean isWarnEnabled() {
567
568 return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
569 }
570
571
572 /***
573 * Return the thread context class loader if available.
574 * Otherwise return null.
575 *
576 * The thread context class loader is available for JDK 1.2
577 * or later, if certain security conditions are met.
578 *
579 * @exception LogConfigurationException if a suitable class loader
580 * cannot be identified.
581 */
582 private static ClassLoader getContextClassLoader()
583 {
584 ClassLoader classLoader = null;
585
586 if (classLoader == null) {
587 try {
588
589 Method method = Thread.class.getMethod("getContextClassLoader", null);
590
591
592 try {
593 classLoader = (ClassLoader)method.invoke(Thread.currentThread(), null);
594 } catch (IllegalAccessException e) {
595 ;
596 } catch (InvocationTargetException e) {
597 /***
598 * InvocationTargetException is thrown by 'invoke' when
599 * the method being invoked (getContextClassLoader) throws
600 * an exception.
601 *
602 * getContextClassLoader() throws SecurityException when
603 * the context class loader isn't an ancestor of the
604 * calling class's class loader, or if security
605 * permissions are restricted.
606 *
607 * In the first case (not related), we want to ignore and
608 * keep going. We cannot help but also ignore the second
609 * with the logic below, but other calls elsewhere (to
610 * obtain a class loader) will trigger this exception where
611 * we can make a distinction.
612 */
613 if (e.getTargetException() instanceof SecurityException) {
614 ;
615 } else {
616
617
618 throw new LogConfigurationException
619 ("Unexpected InvocationTargetException", e.getTargetException());
620 }
621 }
622 } catch (NoSuchMethodException e) {
623
624 ;
625 }
626 }
627
628 if (classLoader == null) {
629 classLoader = SimpleLog.class.getClassLoader();
630 }
631
632
633 return classLoader;
634 }
635
636 private static InputStream getResourceAsStream(final String name)
637 {
638 return (InputStream)AccessController.doPrivileged(
639 new PrivilegedAction() {
640 public Object run() {
641 ClassLoader threadCL = getContextClassLoader();
642
643 if (threadCL != null) {
644 return threadCL.getResourceAsStream(name);
645 } else {
646 return ClassLoader.getSystemResourceAsStream(name);
647 }
648 }
649 });
650 }
651 }
652