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 399221 2006-05-03 09:20:24Z dennisl $
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 * Logs a message with
364 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
365 *
366 * @param message to log
367 * @see org.apache.commons.logging.Log#debug(Object)
368 */
369 public final void debug(Object message) {
370
371 if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
372 log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
373 }
374 }
375
376
377 /***
378 * Logs a message with
379 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
380 *
381 * @param message to log
382 * @param t log this cause
383 * @see org.apache.commons.logging.Log#debug(Object, Throwable)
384 */
385 public final void debug(Object message, Throwable t) {
386
387 if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
388 log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
389 }
390 }
391
392
393 /***
394 * Logs a message with
395 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
396 *
397 * @param message to log
398 * @see org.apache.commons.logging.Log#trace(Object)
399 */
400 public final void trace(Object message) {
401
402 if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
403 log(SimpleLog.LOG_LEVEL_TRACE, message, null);
404 }
405 }
406
407
408 /***
409 * Logs a message with
410 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
411 *
412 * @param message to log
413 * @param t log this cause
414 * @see org.apache.commons.logging.Log#trace(Object, Throwable)
415 */
416 public final void trace(Object message, Throwable t) {
417
418 if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
419 log(SimpleLog.LOG_LEVEL_TRACE, message, t);
420 }
421 }
422
423
424 /***
425 * Logs a message with
426 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
427 *
428 * @param message to log
429 * @see org.apache.commons.logging.Log#info(Object)
430 */
431 public final void info(Object message) {
432
433 if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
434 log(SimpleLog.LOG_LEVEL_INFO,message,null);
435 }
436 }
437
438
439 /***
440 * Logs a message with
441 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
442 *
443 * @param message to log
444 * @param t log this cause
445 * @see org.apache.commons.logging.Log#info(Object, Throwable)
446 */
447 public final void info(Object message, Throwable t) {
448
449 if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
450 log(SimpleLog.LOG_LEVEL_INFO, message, t);
451 }
452 }
453
454
455 /***
456 * Logs a message with
457 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
458 *
459 * @param message to log
460 * @see org.apache.commons.logging.Log#warn(Object)
461 */
462 public final void warn(Object message) {
463
464 if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
465 log(SimpleLog.LOG_LEVEL_WARN, message, null);
466 }
467 }
468
469
470 /***
471 * Logs a message with
472 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
473 *
474 * @param message to log
475 * @param t log this cause
476 * @see org.apache.commons.logging.Log#warn(Object, Throwable)
477 */
478 public final void warn(Object message, Throwable t) {
479
480 if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
481 log(SimpleLog.LOG_LEVEL_WARN, message, t);
482 }
483 }
484
485
486 /***
487 * Logs a message with
488 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
489 *
490 * @param message to log
491 * @see org.apache.commons.logging.Log#error(Object)
492 */
493 public final void error(Object message) {
494
495 if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
496 log(SimpleLog.LOG_LEVEL_ERROR, message, null);
497 }
498 }
499
500
501 /***
502 * Logs a message with
503 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
504 *
505 * @param message to log
506 * @param t log this cause
507 * @see org.apache.commons.logging.Log#error(Object, Throwable)
508 */
509 public final void error(Object message, Throwable t) {
510
511 if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
512 log(SimpleLog.LOG_LEVEL_ERROR, message, t);
513 }
514 }
515
516
517 /***
518 * Log a message with
519 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
520 *
521 * @param message to log
522 * @see org.apache.commons.logging.Log#fatal(Object)
523 */
524 public final void fatal(Object message) {
525
526 if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
527 log(SimpleLog.LOG_LEVEL_FATAL, message, null);
528 }
529 }
530
531
532 /***
533 * Logs a message with
534 * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
535 *
536 * @param message to log
537 * @param t log this cause
538 * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
539 */
540 public final void fatal(Object message, Throwable t) {
541
542 if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
543 log(SimpleLog.LOG_LEVEL_FATAL, message, t);
544 }
545 }
546
547
548 /***
549 * <p> Are debug messages currently enabled? </p>
550 *
551 * <p> This allows expensive operations such as <code>String</code>
552 * concatenation to be avoided when the message will be ignored by the
553 * logger. </p>
554 */
555 public final boolean isDebugEnabled() {
556
557 return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
558 }
559
560
561 /***
562 * <p> Are error messages currently enabled? </p>
563 *
564 * <p> This allows expensive operations such as <code>String</code>
565 * concatenation to be avoided when the message will be ignored by the
566 * logger. </p>
567 */
568 public final boolean isErrorEnabled() {
569
570 return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
571 }
572
573
574 /***
575 * <p> Are fatal messages currently enabled? </p>
576 *
577 * <p> This allows expensive operations such as <code>String</code>
578 * concatenation to be avoided when the message will be ignored by the
579 * logger. </p>
580 */
581 public final boolean isFatalEnabled() {
582
583 return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
584 }
585
586
587 /***
588 * <p> Are info messages currently enabled? </p>
589 *
590 * <p> This allows expensive operations such as <code>String</code>
591 * concatenation to be avoided when the message will be ignored by the
592 * logger. </p>
593 */
594 public final boolean isInfoEnabled() {
595
596 return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
597 }
598
599
600 /***
601 * <p> Are trace messages currently enabled? </p>
602 *
603 * <p> This allows expensive operations such as <code>String</code>
604 * concatenation to be avoided when the message will be ignored by the
605 * logger. </p>
606 */
607 public final boolean isTraceEnabled() {
608
609 return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
610 }
611
612
613 /***
614 * <p> Are warn messages currently enabled? </p>
615 *
616 * <p> This allows expensive operations such as <code>String</code>
617 * concatenation to be avoided when the message will be ignored by the
618 * logger. </p>
619 */
620 public final boolean isWarnEnabled() {
621
622 return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
623 }
624
625
626 /***
627 * Return the thread context class loader if available.
628 * Otherwise return null.
629 *
630 * The thread context class loader is available for JDK 1.2
631 * or later, if certain security conditions are met.
632 *
633 * @exception LogConfigurationException if a suitable class loader
634 * cannot be identified.
635 */
636 private static ClassLoader getContextClassLoader()
637 {
638 ClassLoader classLoader = null;
639
640 if (classLoader == null) {
641 try {
642
643 Method method = Thread.class.getMethod("getContextClassLoader",
644 (Class[]) null);
645
646
647 try {
648 classLoader = (ClassLoader)method.invoke(Thread.currentThread(),
649 (Class[]) null);
650 } catch (IllegalAccessException e) {
651 ;
652 } catch (InvocationTargetException e) {
653 /***
654 * InvocationTargetException is thrown by 'invoke' when
655 * the method being invoked (getContextClassLoader) throws
656 * an exception.
657 *
658 * getContextClassLoader() throws SecurityException when
659 * the context class loader isn't an ancestor of the
660 * calling class's class loader, or if security
661 * permissions are restricted.
662 *
663 * In the first case (not related), we want to ignore and
664 * keep going. We cannot help but also ignore the second
665 * with the logic below, but other calls elsewhere (to
666 * obtain a class loader) will trigger this exception where
667 * we can make a distinction.
668 */
669 if (e.getTargetException() instanceof SecurityException) {
670 ;
671 } else {
672
673
674 throw new LogConfigurationException
675 ("Unexpected InvocationTargetException", e.getTargetException());
676 }
677 }
678 } catch (NoSuchMethodException e) {
679
680 ;
681 }
682 }
683
684 if (classLoader == null) {
685 classLoader = SimpleLog.class.getClassLoader();
686 }
687
688
689 return classLoader;
690 }
691
692 private static InputStream getResourceAsStream(final String name)
693 {
694 return (InputStream)AccessController.doPrivileged(
695 new PrivilegedAction() {
696 public Object run() {
697 ClassLoader threadCL = getContextClassLoader();
698
699 if (threadCL != null) {
700 return threadCL.getResourceAsStream(name);
701 } else {
702 return ClassLoader.getSystemResourceAsStream(name);
703 }
704 }
705 });
706 }
707 }
708