001: /* Log.java
002:
003: {{IS_NOTE
004:
005: Purpose: The logging utilities
006: Description:
007: History:
008: 2001/11/07 14:55:06, Create, Tom M. Yeh.
009: }}IS_NOTE
010:
011: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
012:
013: {{IS_RIGHT
014: This program is distributed under GPL Version 2.0 in the hope that
015: it will be useful, but WITHOUT ANY WARRANTY.
016: }}IS_RIGHT
017: */
018: package org.zkoss.util.logging;
019:
020: import java.util.logging.Logger;
021: import java.util.logging.LogManager;
022: import java.util.logging.Level;
023: import java.util.logging.Handler;
024:
025: import org.zkoss.lang.D;
026: import org.zkoss.lang.Objects;
027: import org.zkoss.lang.Exceptions;
028: import org.zkoss.mesg.Messages;
029:
030: /**
031: * The I3 logger. Usage:
032: *
033: * <p><code>private static final Log log = Log.lookup(MyClass.class);<br>
034: * ...<br>
035: * if (log.debugable()) log.debug("the information to log:"+some);</code>
036: *
037: * <p>{@link Log} is designed to minimize the memory usage by avoiding
038: * unnecessary allocation of java.util.logging.Logger.
039: * In additions, it is possible to use different logger, e.g., log4j,
040: * without affecting the client codes.
041: *
042: * <p>Since this object is very light-weight, it is OK to have
043: * the following statement without using it.<br>
044: * private static final Log log = Log.lookup(MyClass.class);
045: *
046: * <p>To log error or warning, simple use the error and warning method.
047: *
048: * <p>To log info, depending on the complexity you might want to test infoable
049: * first.<br>
050: * <pre><code>log.info("a simple info");
051: *if (log.infoable())
052: * log.info(a + complex + string + operation);</code></pre>
053: *
054: * <p>To log debug information, we usually also test with D.<br>
055: * <pre><code>log.debug("a simple info");
056: *if (D.ON && log.debugable())
057: * log.debug(a + complex + string + operation);</code></pre>
058: *
059: * <p>There is a special level called FINER whose priority is lower than DEBUG.
060: * It is generally used
061: * to log massive debug message under certain situation. In other words,
062: * it is suggested to use the debug methods to log messages as follows:
063: *
064: * <pre><code>if (log.finerable()) {
065: * ... do massive testing and/or printing (use finer)
066: *}</code></pre>
067: *
068: * @author tomyeh
069: */
070: public class Log {
071: /* Don't interfere what a developer might configure its system
072: static {
073: if (D.ON) {
074: Log.class.getClassLoader().setDefaultAssertionStatus(true);
075: Thread.currentThread().getContextClassLoader()
076: .setDefaultAssertionStatus(true);
077: }
078: }*/
079:
080: /** All levels. */
081: public static final Level ALL = Level.ALL;
082: /** The ERROR level. */
083: public static final Level ERROR = Level.SEVERE;
084: /** The WARNING level. */
085: public static final Level WARNING = Level.WARNING;
086: /** The INFO level. */
087: public static final Level INFO = Level.INFO;
088: /** The DEBUG level. */
089: public static final Level DEBUG = Level.FINE;
090: /** The FINER level. */
091: public static final Level FINER = Level.FINER;
092: /** The OFF level used to turn of the logging. */
093: public static final Level OFF = Level.OFF;
094:
095: /** The default name when the loggers don't support hierarchy. */
096: private static final String DEFAULT_NAME = "org.zkoss";
097: //don't change its value since DHtmlLayoutServlet depends on it
098:
099: /** Whether the loggers supports the hierarchy. */
100: private static boolean _hierarchy;
101:
102: /** The category that this log belongs.
103: * Note: it is temporay and set to null when {@link #logger} is called.
104: */
105: private String _name;
106:
107: /** Returns whether the loggers support hierarchy.
108: * If hierarchy is supported, a {@link Log} instance is mapped to
109: * a {@link Logger} instance with the same name. Therefore, it
110: * forms the hierarchical relatiionship among {@link Logger} instances.
111: * It has the best resolution to control which logger to enable.
112: *
113: * <p>On the other hand, if the loggers don't support hierarchy,
114: * all {@link Log} instances are actually mapped to the same
115: * {@link Logger} called "org.zkoss".
116: * The performance is better in this mode.
117: *
118: * <p>Default: false.
119: *
120: * <p>Note: Once {@link LogService} is initialized, {@link #setHierarchy}
121: * is called automatically to turn on the hierarchy support.
122: */
123: public static final boolean isHierarchy() {
124: return _hierarchy;
125: }
126:
127: /** Sets whether to support the hierarchical loggers.
128: */
129: public static final void setHierarchy(boolean hierarchy) {
130: _hierarchy = hierarchy;
131: }
132:
133: /**
134: * Gets the I3 logger based on the class.
135: * @param cls the class that identifies the logger.
136: */
137: public static final Log lookup(Class cls) {
138: return new Log(cls.getName());
139: }
140:
141: /**
142: * Gets the I3 logger based on the giving name.
143: */
144: public static final Log lookup(String name) {
145: return new Log(name);
146: }
147:
148: /** Gets the I3 logger based on the package.
149: */
150: public static final Log lookup(Package pkg) {
151: return new Log(pkg.getName());
152: }
153:
154: /**
155: * The constructor.
156: */
157: protected Log(String name) {
158: if (name == null)
159: throw new IllegalArgumentException(name);
160: _name = name;
161: }
162:
163: /** Returns the name of this logger.
164: */
165: public final String getName() {
166: return _name;
167: }
168:
169: /** Returns the logger (never null).
170: * <p>If not found, it created a new one.
171: */
172: private final Logger getLogger() {
173: return Logger.getLogger(_hierarchy ? _name : DEFAULT_NAME);
174: //NOTE: we don't cache getLogger because Tomcat use one
175: //LogManager per Web app
176: }
177:
178: /** Returns the closest logger that has been created (never null).
179: */
180: private final Logger getClosestLogger() {
181: if (!_hierarchy)
182: return Logger.getLogger(DEFAULT_NAME);
183:
184: final LogManager logman = LogManager.getLogManager();
185: int j = _name.length();
186: do {
187: final Logger logger = logman.getLogger(_name
188: .substring(0, j));
189: if (logger != null)
190: return logger;
191: j = _name.lastIndexOf('.', j - 1);
192: } while (j >= 0);
193: return Logger.getLogger(DEFAULT_NAME);
194: }
195:
196: /** Returns the logger, or null if not created yet.
197: */
198: private final Logger getLoggerIfAny() {
199: return LogManager.getLogManager().getLogger(
200: _hierarchy ? _name : DEFAULT_NAME);
201: }
202:
203: /**
204: * Retruns the logging level.
205: */
206: public final Level getLevel() {
207: final Logger logger = getLoggerIfAny();
208: return logger != null ? logger.getLevel() : null;
209: }
210:
211: /**
212: * Sets the logging level.
213: */
214: public final void setLevel(Level level) {
215: getLogger().setLevel(level);
216: }
217:
218: /** Return the logging level of the specified string.
219: * @return the level; null if no match at all
220: */
221: public static final Level getLevel(String level) {
222: if (level != null) {
223: level = level.toUpperCase();
224: if (level.equals("DEBUG"))
225: return Log.DEBUG;
226: if (level.equals("ERROR"))
227: return Log.ERROR;
228: if (level.equals("FINER"))
229: return Log.FINER;
230: if (level.equals("INFO"))
231: return Log.INFO;
232: if (level.equals("WARNING"))
233: return Log.WARNING;
234: if (level.equals("OFF"))
235: return Log.OFF;
236: }
237: return null;
238: }
239:
240: /**
241: * Tests whether the {@link #WARNING} level is loggable.
242: */
243: public final boolean warningable() {
244: return getClosestLogger().isLoggable(WARNING);
245: }
246:
247: /**
248: * Tests whether the {@link #INFO} level is loggable.
249: */
250: public final boolean infoable() {
251: return getClosestLogger().isLoggable(INFO);
252: }
253:
254: /**
255: * Tests whether the {@link #DEBUG} level is loggable.
256: */
257: public final boolean debugable() {
258: return getClosestLogger().isLoggable(DEBUG);
259: }
260:
261: /**
262: * Tests whether the {@link #FINER} level is loggable.
263: */
264: public final boolean finerable() {
265: return getClosestLogger().isLoggable(FINER);
266: }
267:
268: /**
269: * Logs a message and a throwable object at the giving level.
270: *
271: * <p>All log methods eventaully invokes this method to log messages.
272: *
273: * @param t the throwable object; null to ignore
274: */
275: public final void log(Level level, String msg, Throwable t) {
276: final Logger logger = getClosestLogger();
277: if (logger.isLoggable(level)) {
278: //We have to unveil the stack frame to find the real source
279: //Otherwise, Logger.log will report the wrong source
280: //We cannot skip the first few frames because optimizer might
281: //preserve all frames
282: StackTraceElement[] stack = new Throwable().getStackTrace();
283: String cname = "", mname = "";
284: for (int j = 0; j < stack.length; ++j) {
285: if (!stack[j].getClassName().equals(
286: "org.zkoss.util.logging.Log")) {
287: cname = stack[j].getClassName();
288: mname = stack[j].getMethodName() + ':'
289: + stack[j].getLineNumber();
290: break;
291: }
292: }
293:
294: if (t != null)
295: logger.logp(level, cname, mname, msg, t);
296: else
297: logger.logp(level, cname, mname, msg);
298: }
299: }
300:
301: /**
302: * Logs any object and a throwable object at the giving level.
303: *
304: * @param obj the object whose toString method is called to get the message
305: */
306: public final void log(Level level, Object obj, Throwable t) {
307: log(level, Objects.toString(obj), t);
308: }
309:
310: /**
311: * Logs a message and a throwable object at the giving level
312: * by giving a message code and multiple format arguments.
313: *
314: * @param t the throwable object; null to ignore
315: */
316: public final void log(Level level, int code, Object[] fmtArgs,
317: Throwable t) {
318: log(level, Messages.get(code, fmtArgs), t);
319: }
320:
321: /**
322: * Logs a message and a throwable object at the giving level
323: * by giving a message code and ONE format argument.
324: *
325: * @param t the throwable object; null to ignore
326: */
327: public final void log(Level level, int code, Object fmtArg,
328: Throwable t) {
329: log(level, Messages.get(code, fmtArg), t);
330: }
331:
332: /**
333: * Logs a message and a throwable object at the giving level
334: * by giving a message code and NO format argument.
335: *
336: * @param t the throwable object; null to ignore
337: */
338: public final void log(Level level, int code, Throwable t) {
339: log(level, Messages.get(code), t);
340: }
341:
342: //-- ERROR --//
343: /**
344: * Logs an error message and a throwable object.
345: *
346: * <p>Since error messages hardly happens and are rarely disabled,
347: * there is no method like infoable or debuggable.
348: */
349: public final void error(String msg, Throwable t) {
350: log(ERROR, msg, t);
351: }
352:
353: /**
354: * Logs an error message.
355: */
356: public final void error(String msg) {
357: log(ERROR, msg, null);
358: }
359:
360: /**
361: * Logs an object, whose toString returns the error message,
362: * and a throwable object.
363: *
364: * @param obj the object whose toString method is called to get the message
365: */
366: public final void error(Object obj, Throwable t) {
367: log(ERROR, obj, t);
368: }
369:
370: /**
371: * Logs an object, whose toString returns the error message.
372: *
373: * @param obj the object whose toString method is called to get the message
374: */
375: public final void error(Object obj) {
376: log(ERROR, obj, null);
377: }
378:
379: /**
380: * Logs an error throwable object.
381: */
382: public final void error(Throwable t) {
383: log(ERROR, "", t);
384: }
385:
386: /**
387: * Logs an error message and a throwable object by giving message code.
388: */
389: public final void error(int code, Object[] fmtArgs, Throwable t) {
390: log(ERROR, code, fmtArgs, t);
391: }
392:
393: /**
394: * Logs an error message and a throwable object by giving message code.
395: */
396: public final void error(int code, Object fmtArg, Throwable t) {
397: log(ERROR, code, fmtArg, t);
398: }
399:
400: /**
401: * Logs an error message and a throwable object by giving message code.
402: */
403: public final void error(int code, Throwable t) {
404: log(ERROR, code, t);
405: }
406:
407: /**
408: * Logs an error message by giving message code.
409: */
410: public final void error(int code, Object[] fmtArgs) {
411: log(ERROR, code, fmtArgs, null);
412: }
413:
414: /**
415: * Logs an error message by giving message code.
416: */
417: public final void error(int code, Object fmtArg) {
418: log(ERROR, code, fmtArg, null);
419: }
420:
421: /**
422: * Logs an error message by giving message code.
423: */
424: public final void error(int code) {
425: log(ERROR, code, null);
426: }
427:
428: //-- WARNING --//
429: /**
430: * Logs a warning message and a throwable object.
431: *
432: * <p>Since warning messages are rarely disabled,
433: * there is no method like infoable or debuggable.
434: */
435: public final void warning(String msg, Throwable t) {
436: log(WARNING, msg, t);
437: }
438:
439: /**
440: * Logs a warning message.
441: */
442: public final void warning(String msg) {
443: log(WARNING, msg, null);
444: }
445:
446: /**
447: * Logs an object, whose toString returns the warning message,
448: * and a throwable object.
449: *
450: * @param obj the object whose toString method is called to get the message
451: */
452: public final void warning(Object obj, Throwable t) {
453: log(WARNING, obj, t);
454: }
455:
456: /**
457: * Logs an object, whose toString returns the warning message.
458: *
459: * @param obj the object whose toString method is called to get the message
460: */
461: public final void warning(Object obj) {
462: log(WARNING, obj, null);
463: }
464:
465: /**
466: * Logs a warning throwable object.
467: */
468: public final void warning(Throwable t) {
469: log(WARNING, "", t);
470: }
471:
472: /**
473: * Logs a warning message and a throwable object by giving message code.
474: */
475: public final void warning(int code, Object[] fmtArgs, Throwable t) {
476: log(WARNING, code, fmtArgs, t);
477: }
478:
479: /**
480: * Logs a warning message and a throwable object by giving message code.
481: */
482: public final void warning(int code, Object fmtArg, Throwable t) {
483: log(WARNING, code, fmtArg, t);
484: }
485:
486: /**
487: * Logs a warning message and a throwable object by giving message code.
488: */
489: public final void warning(int code, Throwable t) {
490: log(WARNING, code, t);
491: }
492:
493: /**
494: * Logs a warning message by giving message code.
495: */
496: public final void warning(int code, Object[] fmtArgs) {
497: log(WARNING, code, fmtArgs, null);
498: }
499:
500: /**
501: * Logs a warning message by giving message code.
502: */
503: public final void warning(int code, Object fmtArg) {
504: log(WARNING, code, fmtArg, null);
505: }
506:
507: /**
508: * Logs a warning message by giving message code.
509: */
510: public final void warning(int code) {
511: log(WARNING, code, null);
512: }
513:
514: //-- INFO --//
515: /**
516: * Logs an info message and a throwable object.
517: *
518: * <p>Since info messages are rarely disabled,
519: * there is no method like infoable or debuggable.
520: */
521: public final void info(String msg, Throwable t) {
522: log(INFO, msg, t);
523: }
524:
525: /**
526: * Logs an info message.
527: */
528: public final void info(String msg) {
529: log(INFO, msg, null);
530: }
531:
532: /**
533: * Logs an object, whose toString returns the info message,
534: * and a throwable object.
535: *
536: * @param obj the object whose toString method is called to get the message
537: */
538: public final void info(Object obj, Throwable t) {
539: log(INFO, obj, t);
540: }
541:
542: /**
543: * Logs an object, whose toString returns the info message.
544: *
545: * @param obj the object whose toString method is called to get the message
546: */
547: public final void info(Object obj) {
548: log(INFO, obj, null);
549: }
550:
551: /**
552: * Logs an info throwable object.
553: */
554: public final void info(Throwable t) {
555: log(INFO, "", t);
556: }
557:
558: /**
559: * Logs an info message and a throwable object by giving message code.
560: */
561: public final void info(int code, Object[] fmtArgs, Throwable t) {
562: log(INFO, code, fmtArgs, t);
563: }
564:
565: /**
566: * Logs an info message and a throwable object by giving message code.
567: */
568: public final void info(int code, Object fmtArg, Throwable t) {
569: log(INFO, code, fmtArg, t);
570: }
571:
572: /**
573: * Logs an info message and a throwable object by giving message code.
574: */
575: public final void info(int code, Throwable t) {
576: log(INFO, code, t);
577: }
578:
579: /**
580: * Logs an info message by giving message code.
581: */
582: public final void info(int code, Object[] fmtArgs) {
583: log(INFO, code, fmtArgs, null);
584: }
585:
586: /**
587: * Logs an info message by giving message code.
588: */
589: public final void info(int code, Object fmtArg) {
590: log(INFO, code, fmtArg, null);
591: }
592:
593: /**
594: * Logs an info message by giving message code.
595: */
596: public final void info(int code) {
597: log(INFO, code, null);
598: }
599:
600: //-- DEBUG --//
601: /**
602: * Logs a debug message and a throwable object.
603: *
604: * <p>Since debug messages are rarely disabled,
605: * there is no method like infoable or debuggable.
606: */
607: public final void debug(String msg, Throwable t) {
608: log(DEBUG, msg, t);
609: }
610:
611: /**
612: * Logs a debug message.
613: */
614: public final void debug(String msg) {
615: log(DEBUG, msg, null);
616: }
617:
618: /**
619: * Logs an object, whose toString returns the debug message,
620: * and a throwable object.
621: *
622: * @param obj the object whose toString method is called to get the message
623: */
624: public final void debug(Object obj, Throwable t) {
625: log(DEBUG, obj, t);
626: }
627:
628: /**
629: * Logs an object, whose toString returns the debug message.
630: *
631: * @param obj the object whose toString method is called to get the message
632: */
633: public final void debug(Object obj) {
634: log(DEBUG, obj, null);
635: }
636:
637: /**
638: * Logs a debug throwable object.
639: */
640: public final void debug(Throwable t) {
641: log(DEBUG, "", t);
642: }
643:
644: /**
645: * Logs a debug message and a throwable object by giving message code.
646: */
647: public final void debug(int code, Object[] fmtArgs, Throwable t) {
648: log(DEBUG, code, fmtArgs, t);
649: }
650:
651: /**
652: * Logs a debug message and a throwable object by giving message code.
653: */
654: public final void debug(int code, Object fmtArg, Throwable t) {
655: log(DEBUG, code, fmtArg, t);
656: }
657:
658: /**
659: * Logs a debug message and a throwable object by giving message code.
660: */
661: public final void debug(int code, Throwable t) {
662: log(DEBUG, code, t);
663: }
664:
665: /**
666: * Logs a debug message by giving message code.
667: */
668: public final void debug(int code, Object[] fmtArgs) {
669: log(DEBUG, code, fmtArgs, null);
670: }
671:
672: /**
673: * Logs a debug message by giving message code.
674: */
675: public final void debug(int code, Object fmtArg) {
676: log(DEBUG, code, fmtArg, null);
677: }
678:
679: /**
680: * Logs a debug message by giving message code.
681: */
682: public final void debug(int code) {
683: log(DEBUG, code, null);
684: }
685:
686: //-- FINER --//
687: /**
688: * Logs a finer message and a throwable object.
689: */
690: public final void finer(String msg, Throwable t) {
691: log(FINER, msg, t);
692: }
693:
694: /**
695: * Logs a finer message.
696: */
697: public final void finer(String msg) {
698: log(FINER, msg, null);
699: }
700:
701: /**
702: * Logs an object, whose toString returns the finer message,
703: * and a throwable object.
704: *
705: * @param obj the object whose toString method is called to get the message
706: */
707: public final void finer(Object obj, Throwable t) {
708: log(FINER, obj, t);
709: }
710:
711: /**
712: * Logs an object, whose toString returns the finer message.
713: *
714: * @param obj the object whose toString method is called to get the message
715: */
716: public final void finer(Object obj) {
717: log(FINER, obj, null);
718: }
719:
720: /**
721: * Logs a finer throwable object.
722: */
723: public final void finer(Throwable t) {
724: log(FINER, "", t);
725: }
726:
727: /**
728: * Logs a finer message and a throwable object by giving message code.
729: */
730: public final void finer(int code, Object[] fmtArgs, Throwable t) {
731: log(FINER, code, fmtArgs, t);
732: }
733:
734: /**
735: * Logs a finer message and a throwable object by giving message code.
736: */
737: public final void finer(int code, Object fmtArg, Throwable t) {
738: log(FINER, code, fmtArg, t);
739: }
740:
741: /**
742: * Logs a finer message and a throwable object by giving message code.
743: */
744: public final void finer(int code, Throwable t) {
745: log(FINER, code, t);
746: }
747:
748: /**
749: * Logs a finer message by giving message code.
750: */
751: public final void finer(int code, Object[] fmtArgs) {
752: log(FINER, code, fmtArgs, null);
753: }
754:
755: /**
756: * Logs a finer message by giving message code.
757: */
758: public final void finer(int code, Object fmtArg) {
759: log(FINER, code, fmtArg, null);
760: }
761:
762: /**
763: * Logs a finer message by giving message code.
764: */
765: public final void finer(int code) {
766: log(FINER, code, null);
767: }
768:
769: /** Logs only the real cause of the specified exception.
770: * It is useful because sometimes the stack trace is too big.
771: */
772: public final void realCause(Throwable ex) {
773: realCause(null, ex);
774: }
775:
776: /** Logs only the real cause of the specified exception with an extra
777: * message as an error message.
778: */
779: public final void realCause(String message, Throwable ex) {
780: realCause0(message, ex, true, 0);
781: }
782:
783: /** Logs only the first few lines of the real cause as an error message.
784: */
785: public final void realCauseBriefly(String message, Throwable ex) {
786: realCause0(message, ex, true, 5);
787: }
788:
789: /** Lo only the first few lines of the real cause as an error message.
790: */
791: public final void realCauseBriefly(Throwable ex) {
792: realCauseBriefly(null, ex);
793: }
794:
795: private final void realCause0(String message, Throwable ex,
796: boolean err, int maxcnt) {
797: final StringBuffer sb = new StringBuffer(1024);
798: if (message != null)
799: sb.append(message).append('\n');
800:
801: while (true) {
802: Throwable cause = Exceptions.getCause(ex);
803: if (cause == null)
804: break;
805: sb.append(">>").append(ex.getClass().getName())
806: .append(": ").append(ex.getMessage()).append('\n');
807: ex = cause;
808: }
809:
810: String s = Exceptions.getExtraMessage(ex);
811: if (s != null)
812: sb.append(s).append('\n');
813:
814: message = Exceptions.formatStackTrace(sb, ex, ">>", maxcnt)
815: .toString();
816: if (err)
817: error(message);
818: else
819: warning(message);
820: }
821:
822: /** Logs only the first few lines of the real cause as an warning message.
823: */
824: public final void warningBriefly(String message, Throwable ex) {
825: realCause0(message, ex, false, 3);
826: }
827:
828: /** Lo only the first few lines of the real cause.
829: */
830: public final void warningBriefly(Throwable ex) {
831: warningBriefly(null, ex);
832: }
833:
834: /** Logs an exception as an warning message about being eaten
835: * (rather than thrown).
836: */
837: public final void eat(String message, Throwable ex) {
838: if (debugable()) {
839: warningBriefly(message, ex);
840: } else {
841: warning(Objects.BAR1_STRING
842: + (message != null ? "\n" + message : "")
843: + "\n"
844: + "The exception:\n"
845: + Exceptions.getMessage(ex)
846: + "\n"
847: + "If you want to see the stack trace, turn the DEBUG level on for "
848: + _name + "\n" + Objects.BAR1_STRING);
849: }
850: }
851:
852: /** Logs an exception as an warning message about being eaten
853: * (rather than thrown).
854: */
855: public final void eat(Throwable ex) {
856: eat(null, ex);
857: }
858:
859: public int hashCode() {
860: return _name.hashCode();
861: }
862:
863: public boolean equals(Object o) {
864: return o instanceof Log && ((Log) o)._name.equals(_name);
865: }
866:
867: public String toString() {
868: return _name;
869: }
870: }
|