GNU Classpath (0.97.2) | |
Frames | No Frames |
1: /* Logger.java -- a class for logging messages 2: Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.util.logging; 40: 41: import java.util.List; 42: import java.util.MissingResourceException; 43: import java.util.ResourceBundle; 44: import java.security.AccessController; 45: import java.security.PrivilegedAction; 46: 47: /** 48: * A Logger is used for logging information about events. Usually, there is a 49: * seprate logger for each subsystem or component, although there is a shared 50: * instance for components that make only occasional use of the logging 51: * framework. 52: * <p> 53: * It is common to name a logger after the name of a corresponding Java package. 54: * Loggers are organized into a hierarchical namespace; for example, the logger 55: * <code>"org.gnu.foo"</code> is the <em>parent</em> of logger 56: * <code>"org.gnu.foo.bar"</code>. 57: * <p> 58: * A logger for a named subsystem can be obtained through {@link 59: * java.util.logging.Logger#getLogger(java.lang.String)}. However, only code 60: * which has been granted the permission to control the logging infrastructure 61: * will be allowed to customize that logger. Untrusted code can obtain a 62: * private, anonymous logger through {@link #getAnonymousLogger()} if it wants 63: * to perform any modifications to the logger. 64: * <p> 65: * FIXME: Write more documentation. 66: * 67: * @author Sascha Brawer (brawer@acm.org) 68: */ 69: public class Logger 70: { 71: static final Logger root = new Logger("", null); 72: 73: /** 74: * A logger provided to applications that make only occasional use of the 75: * logging framework, typically early prototypes. Serious products are 76: * supposed to create and use their own Loggers, so they can be controlled 77: * individually. 78: */ 79: public static final Logger global; 80: 81: /** 82: * Use to lock methods on this class instead of calling synchronize on methods 83: * to avoid deadlocks. Yeah, no kidding, we got them :) 84: */ 85: private static final Object[] lock = new Object[0]; 86: 87: static 88: { 89: // Our class might be initialized from an unprivileged context 90: global = (Logger) AccessController.doPrivileged(new PrivilegedAction() 91: { 92: public Object run() 93: { 94: return getLogger("global"); 95: } 96: }); 97: } 98: 99: /** 100: * The name of the Logger, or <code>null</code> if the logger is anonymous. 101: * <p> 102: * A previous version of the GNU Classpath implementation granted untrusted 103: * code the permission to control any logger whose name was null. However, 104: * test code revealed that the Sun J2SE 1.4 reference implementation enforces 105: * the security control for any logger that was not created through 106: * getAnonymousLogger, even if it has a null name. Therefore, a separate flag 107: * {@link Logger#anonymous} was introduced. 108: */ 109: private final String name; 110: 111: /** 112: * The name of the resource bundle used for localization. 113: * <p> 114: * This variable cannot be declared as <code>final</code> because its value 115: * can change as a result of calling getLogger(String,String). 116: */ 117: private String resourceBundleName; 118: 119: /** 120: * The resource bundle used for localization. 121: * <p> 122: * This variable cannot be declared as <code>final</code> because its value 123: * can change as a result of calling getLogger(String,String). 124: */ 125: private ResourceBundle resourceBundle; 126: 127: private Filter filter; 128: 129: private final List handlerList = new java.util.ArrayList(4); 130: 131: private Handler[] handlers = new Handler[0]; 132: 133: /** 134: * Indicates whether or not this logger is anonymous. While a 135: * LoggingPermission is required for any modifications to a normal logger, 136: * untrusted code can obtain an anonymous logger and modify it according to 137: * its needs. 138: * <p> 139: * A previous version of the GNU Classpath implementation granted access to 140: * every logger whose name was null. However, test code revealed that the Sun 141: * J2SE 1.4 reference implementation enforces the security control for any 142: * logger that was not created through getAnonymousLogger, even if it has a 143: * null name. 144: */ 145: private boolean anonymous; 146: 147: private boolean useParentHandlers; 148: 149: private Level level; 150: 151: private Logger parent; 152: 153: /** 154: * Constructs a Logger for a subsystem. Most applications do not need to 155: * create new Loggers explicitly; instead, they should call the static factory 156: * methods {@link #getLogger(java.lang.String,java.lang.String) getLogger} 157: * (with ResourceBundle for localization) or 158: * {@link #getLogger(java.lang.String) getLogger} (without ResourceBundle), 159: * respectively. 160: * 161: * @param name the name for the logger, for example "java.awt" or 162: * "com.foo.bar". The name should be based on the name of the 163: * package issuing log records and consist of dot-separated Java 164: * identifiers. 165: * @param resourceBundleName the name of a resource bundle for localizing 166: * messages, or <code>null</code> to indicate that messages do 167: * not need to be localized. 168: * @throws java.util.MissingResourceException if 169: * <code>resourceBundleName</code> is not <code>null</code> 170: * and no such bundle could be located. 171: */ 172: protected Logger(String name, String resourceBundleName) 173: throws MissingResourceException 174: { 175: this.name = name; 176: this.resourceBundleName = resourceBundleName; 177: 178: if (resourceBundleName == null) 179: resourceBundle = null; 180: else 181: resourceBundle = ResourceBundle.getBundle(resourceBundleName); 182: 183: level = null; 184: 185: /* 186: * This is null when the root logger is being constructed, and the root 187: * logger afterwards. 188: */ 189: parent = root; 190: 191: useParentHandlers = (parent != null); 192: } 193: 194: /** 195: * Finds a registered logger for a subsystem, or creates one in case no logger 196: * has been registered yet. 197: * 198: * @param name the name for the logger, for example "java.awt" or 199: * "com.foo.bar". The name should be based on the name of the 200: * package issuing log records and consist of dot-separated Java 201: * identifiers. 202: * @throws IllegalArgumentException if a logger for the subsystem identified 203: * by <code>name</code> has already been created, but uses a a 204: * resource bundle for localizing messages. 205: * @throws NullPointerException if <code>name</code> is <code>null</code>. 206: * @return a logger for the subsystem specified by <code>name</code> that 207: * does not localize messages. 208: */ 209: public static Logger getLogger(String name) 210: { 211: return getLogger(name, null); 212: } 213: 214: /** 215: * Finds a registered logger for a subsystem, or creates one in case no logger 216: * has been registered yet. 217: * <p> 218: * If a logger with the specified name has already been registered, the 219: * behavior depends on the resource bundle that is currently associated with 220: * the existing logger. 221: * <ul> 222: * <li>If the existing logger uses the same resource bundle as specified by 223: * <code>resourceBundleName</code>, the existing logger is returned.</li> 224: * <li>If the existing logger currently does not localize messages, the 225: * existing logger is modified to use the bundle specified by 226: * <code>resourceBundleName</code>. The existing logger is then returned. 227: * Therefore, all subsystems currently using this logger will produce 228: * localized messages from now on.</li> 229: * <li>If the existing logger already has an associated resource bundle, but 230: * a different one than specified by <code>resourceBundleName</code>, an 231: * <code>IllegalArgumentException</code> is thrown.</li> 232: * </ul> 233: * 234: * @param name the name for the logger, for example "java.awt" or 235: * "org.gnu.foo". The name should be based on the name of the 236: * package issuing log records and consist of dot-separated Java 237: * identifiers. 238: * @param resourceBundleName the name of a resource bundle for localizing 239: * messages, or <code>null</code> to indicate that messages do 240: * not need to be localized. 241: * @return a logger for the subsystem specified by <code>name</code>. 242: * @throws java.util.MissingResourceException if 243: * <code>resourceBundleName</code> is not <code>null</code> 244: * and no such bundle could be located. 245: * @throws IllegalArgumentException if a logger for the subsystem identified 246: * by <code>name</code> has already been created, but uses a 247: * different resource bundle for localizing messages. 248: * @throws NullPointerException if <code>name</code> is <code>null</code>. 249: */ 250: public static Logger getLogger(String name, String resourceBundleName) 251: { 252: LogManager lm = LogManager.getLogManager(); 253: Logger result; 254: 255: if (name == null) 256: throw new NullPointerException(); 257: 258: /* 259: * Without synchronized(lm), it could happen that another thread would 260: * create a logger between our calls to getLogger and addLogger. While 261: * addLogger would indicate this by returning false, we could not be sure 262: * that this other logger was still existing when we called getLogger a 263: * second time in order to retrieve it -- note that LogManager is only 264: * allowed to keep weak references to registered loggers, so Loggers can be 265: * garbage collected at any time in general, and between our call to 266: * addLogger and our second call go getLogger in particular. Of course, we 267: * assume here that LogManager.addLogger etc. are synchronizing on the 268: * global LogManager object. There is a comment in the implementation of 269: * LogManager.addLogger referring to this comment here, so that any change 270: * in the synchronization of LogManager will be reflected here. 271: */ 272: synchronized (lock) 273: { 274: synchronized (lm) 275: { 276: result = lm.getLogger(name); 277: if (result == null) 278: { 279: boolean couldBeAdded; 280: 281: result = new Logger(name, resourceBundleName); 282: couldBeAdded = lm.addLogger(result); 283: if (! couldBeAdded) 284: throw new IllegalStateException("cannot register new logger"); 285: } 286: else 287: { 288: /* 289: * The logger already exists. Make sure it uses the same 290: * resource bundle for localizing messages. 291: */ 292: String existingBundleName = result.getResourceBundleName(); 293: 294: /* 295: * The Sun J2SE 1.4 reference implementation will return the 296: * registered logger object, even if it does not have a resource 297: * bundle associated with it. However, it seems to change the 298: * resourceBundle of the registered logger to the bundle whose 299: * name was passed to getLogger. 300: */ 301: if ((existingBundleName == null) && 302: (resourceBundleName != null)) 303: { 304: /* 305: * If ResourceBundle.getBundle throws an exception, the 306: * existing logger will be unchanged. This would be 307: * different if the assignment to resourceBundleName came 308: * first. 309: */ 310: result.resourceBundle = 311: ResourceBundle.getBundle(resourceBundleName); 312: 313: result.resourceBundleName = resourceBundleName; 314: return result; 315: } 316: 317: if ((existingBundleName != resourceBundleName) 318: && ((existingBundleName == null) 319: || !existingBundleName.equals(resourceBundleName))) 320: { 321: throw new IllegalArgumentException(); 322: } 323: } 324: } 325: } 326: 327: return result; 328: } 329: 330: /** 331: * Creates a new, unnamed logger. Unnamed loggers are not registered in the 332: * namespace of the LogManager, and no special security permission is required 333: * for changing their state. Therefore, untrusted applets are able to modify 334: * their private logger instance obtained through this method. 335: * <p> 336: * The parent of the newly created logger will the the root logger, from which 337: * the level threshold and the handlers are inherited. 338: */ 339: public static Logger getAnonymousLogger() 340: { 341: return getAnonymousLogger(null); 342: } 343: 344: /** 345: * Creates a new, unnamed logger. Unnamed loggers are not registered in the 346: * namespace of the LogManager, and no special security permission is required 347: * for changing their state. Therefore, untrusted applets are able to modify 348: * their private logger instance obtained through this method. 349: * <p> 350: * The parent of the newly created logger will the the root logger, from which 351: * the level threshold and the handlers are inherited. 352: * 353: * @param resourceBundleName the name of a resource bundle for localizing 354: * messages, or <code>null</code> to indicate that messages do 355: * not need to be localized. 356: * @throws java.util.MissingResourceException if 357: * <code>resourceBundleName</code> is not <code>null</code> 358: * and no such bundle could be located. 359: */ 360: public static Logger getAnonymousLogger(String resourceBundleName) 361: throws MissingResourceException 362: { 363: Logger result; 364: 365: result = new Logger(null, resourceBundleName); 366: result.anonymous = true; 367: return result; 368: } 369: 370: /** 371: * Returns the name of the resource bundle that is being used for localizing 372: * messages. 373: * 374: * @return the name of the resource bundle used for localizing messages, or 375: * <code>null</code> if the parent's resource bundle is used for 376: * this purpose. 377: */ 378: public String getResourceBundleName() 379: { 380: synchronized (lock) 381: { 382: return resourceBundleName; 383: } 384: } 385: 386: /** 387: * Returns the resource bundle that is being used for localizing messages. 388: * 389: * @return the resource bundle used for localizing messages, or 390: * <code>null</code> if the parent's resource bundle is used for 391: * this purpose. 392: */ 393: public ResourceBundle getResourceBundle() 394: { 395: synchronized (lock) 396: { 397: return resourceBundle; 398: } 399: } 400: 401: /** 402: * Returns the severity level threshold for this <code>Handler</code>. All 403: * log records with a lower severity level will be discarded; a log record of 404: * the same or a higher level will be published unless an installed 405: * <code>Filter</code> decides to discard it. 406: * 407: * @return the severity level below which all log messages will be discarded, 408: * or <code>null</code> if the logger inherits the threshold from 409: * its parent. 410: */ 411: public Level getLevel() 412: { 413: synchronized (lock) 414: { 415: return level; 416: } 417: } 418: 419: /** 420: * Returns whether or not a message of the specified level would be logged by 421: * this logger. 422: * 423: * @throws NullPointerException if <code>level</code> is <code>null</code>. 424: */ 425: public boolean isLoggable(Level level) 426: { 427: synchronized (lock) 428: { 429: if (this.level != null) 430: return this.level.intValue() <= level.intValue(); 431: 432: if (parent != null) 433: return parent.isLoggable(level); 434: else 435: return false; 436: } 437: } 438: 439: /** 440: * Sets the severity level threshold for this <code>Handler</code>. All log 441: * records with a lower severity level will be discarded immediately. A log 442: * record of the same or a higher level will be published unless an installed 443: * <code>Filter</code> decides to discard it. 444: * 445: * @param level the severity level below which all log messages will be 446: * discarded, or <code>null</code> to indicate that the logger 447: * should inherit the threshold from its parent. 448: * @throws SecurityException if this logger is not anonymous, a security 449: * manager exists, and the caller is not granted the permission to 450: * control the logging infrastructure by having 451: * LoggingPermission("control"). Untrusted code can obtain an 452: * anonymous logger through the static factory method 453: * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 454: */ 455: public void setLevel(Level level) 456: { 457: synchronized (lock) 458: { 459: /* 460: * An application is allowed to control an anonymous logger without 461: * having the permission to control the logging infrastructure. 462: */ 463: if (! anonymous) 464: LogManager.getLogManager().checkAccess(); 465: 466: this.level = level; 467: } 468: } 469: 470: public Filter getFilter() 471: { 472: synchronized (lock) 473: { 474: return filter; 475: } 476: } 477: 478: /** 479: * @throws SecurityException if this logger is not anonymous, a security 480: * manager exists, and the caller is not granted the permission to 481: * control the logging infrastructure by having 482: * LoggingPermission("control"). Untrusted code can obtain an 483: * anonymous logger through the static factory method 484: * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 485: */ 486: public void setFilter(Filter filter) throws SecurityException 487: { 488: synchronized (lock) 489: { 490: /* 491: * An application is allowed to control an anonymous logger without 492: * having the permission to control the logging infrastructure. 493: */ 494: if (! anonymous) 495: LogManager.getLogManager().checkAccess(); 496: 497: this.filter = filter; 498: } 499: } 500: 501: /** 502: * Returns the name of this logger. 503: * 504: * @return the name of this logger, or <code>null</code> if the logger is 505: * anonymous. 506: */ 507: public String getName() 508: { 509: /* 510: * Note that the name of a logger cannot be changed during its lifetime, so 511: * no synchronization is needed. 512: */ 513: return name; 514: } 515: 516: /** 517: * Passes a record to registered handlers, provided the record is considered 518: * as loggable both by {@link #isLoggable(Level)} and a possibly installed 519: * custom {@link #setFilter(Filter) filter}. 520: * <p> 521: * If the logger has been configured to use parent handlers, the record will 522: * be forwarded to the parent of this logger in addition to being processed by 523: * the handlers registered with this logger. 524: * <p> 525: * The other logging methods in this class are convenience methods that merely 526: * create a new LogRecord and pass it to this method. Therefore, subclasses 527: * usually just need to override this single method for customizing the 528: * logging behavior. 529: * 530: * @param record the log record to be inspected and possibly forwarded. 531: */ 532: public void log(LogRecord record) 533: { 534: synchronized (lock) 535: { 536: if (!isLoggable(record.getLevel())) 537: return; 538: 539: if ((filter != null) && ! filter.isLoggable(record)) 540: return; 541: 542: /* 543: * If no logger name has been set for the log record, use the name of 544: * this logger. 545: */ 546: if (record.getLoggerName() == null) 547: record.setLoggerName(name); 548: 549: /* 550: * Avoid that some other thread is changing the logger hierarchy while 551: * we are traversing it. 552: */ 553: synchronized (LogManager.getLogManager()) 554: { 555: Logger curLogger = this; 556: 557: do 558: { 559: /* 560: * The Sun J2SE 1.4 reference implementation seems to call the 561: * filter only for the logger whose log method is called, never 562: * for any of its parents. Also, parent loggers publish log 563: * record whatever their level might be. This is pretty weird, 564: * but GNU Classpath tries to be as compatible as possible to 565: * the reference implementation. 566: */ 567: for (int i = 0; i < curLogger.handlers.length; i++) 568: curLogger.handlers[i].publish(record); 569: 570: if (curLogger.getUseParentHandlers() == false) 571: break; 572: 573: curLogger = curLogger.getParent(); 574: } 575: while (parent != null); 576: } 577: } 578: } 579: 580: public void log(Level level, String message) 581: { 582: if (isLoggable(level)) 583: log(level, message, (Object[]) null); 584: } 585: 586: public void log(Level level, String message, Object param) 587: { 588: synchronized (lock) 589: { 590: if (isLoggable(level)) 591: { 592: StackTraceElement caller = getCallerStackFrame(); 593: logp(level, caller != null ? caller.getClassName() : "<unknown>", 594: caller != null ? caller.getMethodName() : "<unknown>", 595: message, param); 596: } 597: } 598: } 599: 600: public void log(Level level, String message, Object[] params) 601: { 602: synchronized (lock) 603: { 604: if (isLoggable(level)) 605: { 606: StackTraceElement caller = getCallerStackFrame(); 607: logp(level, caller != null ? caller.getClassName() : "<unknown>", 608: caller != null ? caller.getMethodName() : "<unknown>", 609: message, params); 610: 611: } 612: } 613: } 614: 615: public void log(Level level, String message, Throwable thrown) 616: { 617: synchronized (lock) 618: { 619: if (isLoggable(level)) 620: { 621: StackTraceElement caller = getCallerStackFrame(); 622: logp(level, caller != null ? caller.getClassName() : "<unknown>", 623: caller != null ? caller.getMethodName() : "<unknown>", 624: message, thrown); 625: } 626: } 627: } 628: 629: public void logp(Level level, String sourceClass, String sourceMethod, 630: String message) 631: { 632: synchronized (lock) 633: { 634: logp(level, sourceClass, sourceMethod, message, (Object[]) null); 635: } 636: } 637: 638: public void logp(Level level, String sourceClass, String sourceMethod, 639: String message, Object param) 640: { 641: synchronized (lock) 642: { 643: logp(level, sourceClass, sourceMethod, message, new Object[] { param }); 644: } 645: 646: } 647: 648: private ResourceBundle findResourceBundle() 649: { 650: synchronized (lock) 651: { 652: if (resourceBundle != null) 653: return resourceBundle; 654: 655: if (parent != null) 656: return parent.findResourceBundle(); 657: 658: return null; 659: } 660: } 661: 662: private void logImpl(Level level, String sourceClass, String sourceMethod, 663: String message, Object[] params) 664: { 665: synchronized (lock) 666: { 667: LogRecord rec = new LogRecord(level, message); 668: 669: rec.setResourceBundle(findResourceBundle()); 670: rec.setSourceClassName(sourceClass); 671: rec.setSourceMethodName(sourceMethod); 672: rec.setParameters(params); 673: 674: log(rec); 675: } 676: } 677: 678: public void logp(Level level, String sourceClass, String sourceMethod, 679: String message, Object[] params) 680: { 681: synchronized (lock) 682: { 683: logImpl(level, sourceClass, sourceMethod, message, params); 684: } 685: } 686: 687: public void logp(Level level, String sourceClass, String sourceMethod, 688: String message, Throwable thrown) 689: { 690: synchronized (lock) 691: { 692: LogRecord rec = new LogRecord(level, message); 693: 694: rec.setResourceBundle(resourceBundle); 695: rec.setSourceClassName(sourceClass); 696: rec.setSourceMethodName(sourceMethod); 697: rec.setThrown(thrown); 698: 699: log(rec); 700: } 701: } 702: 703: public void logrb(Level level, String sourceClass, String sourceMethod, 704: String bundleName, String message) 705: { 706: synchronized (lock) 707: { 708: logrb(level, sourceClass, sourceMethod, bundleName, message, 709: (Object[]) null); 710: } 711: } 712: 713: public void logrb(Level level, String sourceClass, String sourceMethod, 714: String bundleName, String message, Object param) 715: { 716: synchronized (lock) 717: { 718: logrb(level, sourceClass, sourceMethod, bundleName, message, 719: new Object[] { param }); 720: } 721: } 722: 723: public void logrb(Level level, String sourceClass, String sourceMethod, 724: String bundleName, String message, Object[] params) 725: { 726: synchronized (lock) 727: { 728: LogRecord rec = new LogRecord(level, message); 729: 730: rec.setResourceBundleName(bundleName); 731: rec.setSourceClassName(sourceClass); 732: rec.setSourceMethodName(sourceMethod); 733: rec.setParameters(params); 734: 735: log(rec); 736: } 737: } 738: 739: public void logrb(Level level, String sourceClass, String sourceMethod, 740: String bundleName, String message, Throwable thrown) 741: { 742: synchronized (lock) 743: { 744: LogRecord rec = new LogRecord(level, message); 745: 746: rec.setResourceBundleName(bundleName); 747: rec.setSourceClassName(sourceClass); 748: rec.setSourceMethodName(sourceMethod); 749: rec.setThrown(thrown); 750: 751: log(rec); 752: } 753: } 754: 755: public void entering(String sourceClass, String sourceMethod) 756: { 757: synchronized (lock) 758: { 759: if (isLoggable(Level.FINER)) 760: logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); 761: } 762: } 763: 764: public void entering(String sourceClass, String sourceMethod, Object param) 765: { 766: synchronized (lock) 767: { 768: if (isLoggable(Level.FINER)) 769: logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); 770: } 771: } 772: 773: public void entering(String sourceClass, String sourceMethod, Object[] params) 774: { 775: synchronized (lock) 776: { 777: if (isLoggable(Level.FINER)) 778: { 779: StringBuffer buf = new StringBuffer(80); 780: buf.append("ENTRY"); 781: for (int i = 0; i < params.length; i++) 782: { 783: buf.append(" {"); 784: buf.append(i); 785: buf.append('}'); 786: } 787: 788: logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params); 789: } 790: } 791: } 792: 793: public void exiting(String sourceClass, String sourceMethod) 794: { 795: synchronized (lock) 796: { 797: if (isLoggable(Level.FINER)) 798: logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); 799: } 800: } 801: 802: public void exiting(String sourceClass, String sourceMethod, Object result) 803: { 804: synchronized (lock) 805: { 806: if (isLoggable(Level.FINER)) 807: logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); 808: } 809: } 810: 811: public void throwing(String sourceClass, String sourceMethod, Throwable thrown) 812: { 813: synchronized (lock) 814: { 815: if (isLoggable(Level.FINER)) 816: logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown); 817: } 818: } 819: 820: /** 821: * Logs a message with severity level SEVERE, indicating a serious failure 822: * that prevents normal program execution. Messages at this level should be 823: * understandable to an inexperienced, non-technical end user. Ideally, they 824: * explain in simple words what actions the user can take in order to resolve 825: * the problem. 826: * 827: * @see Level#SEVERE 828: * @param message the message text, also used as look-up key if the logger is 829: * localizing messages with a resource bundle. While it is possible 830: * to pass <code>null</code>, this is not recommended, since a 831: * logging message without text is unlikely to be helpful. 832: */ 833: public void severe(String message) 834: { 835: synchronized (lock) 836: { 837: if (isLoggable(Level.SEVERE)) 838: log(Level.SEVERE, message); 839: } 840: } 841: 842: /** 843: * Logs a message with severity level WARNING, indicating a potential problem 844: * that does not prevent normal program execution. Messages at this level 845: * should be understandable to an inexperienced, non-technical end user. 846: * Ideally, they explain in simple words what actions the user can take in 847: * order to resolve the problem. 848: * 849: * @see Level#WARNING 850: * @param message the message text, also used as look-up key if the logger is 851: * localizing messages with a resource bundle. While it is possible 852: * to pass <code>null</code>, this is not recommended, since a 853: * logging message without text is unlikely to be helpful. 854: */ 855: public void warning(String message) 856: { 857: synchronized (lock) 858: { 859: if (isLoggable(Level.WARNING)) 860: log(Level.WARNING, message); 861: } 862: } 863: 864: /** 865: * Logs a message with severity level INFO. {@link Level#INFO} is intended for 866: * purely informational messages that do not indicate error or warning 867: * situations. In the default logging configuration, INFO messages will be 868: * written to the system console. For this reason, the INFO level should be 869: * used only for messages that are important to end users and system 870: * administrators. Messages at this level should be understandable to an 871: * inexperienced, non-technical user. 872: * 873: * @param message the message text, also used as look-up key if the logger is 874: * localizing messages with a resource bundle. While it is possible 875: * to pass <code>null</code>, this is not recommended, since a 876: * logging message without text is unlikely to be helpful. 877: */ 878: public void info(String message) 879: { 880: synchronized (lock) 881: { 882: if (isLoggable(Level.INFO)) 883: log(Level.INFO, message); 884: } 885: } 886: 887: /** 888: * Logs a message with severity level CONFIG. {@link Level#CONFIG} is intended 889: * for static configuration messages, for example about the windowing 890: * environment, the operating system version, etc. 891: * 892: * @param message the message text, also used as look-up key if the logger is 893: * localizing messages with a resource bundle. While it is possible 894: * to pass <code>null</code>, this is not recommended, since a 895: * logging message without text is unlikely to be helpful. 896: */ 897: public void config(String message) 898: { 899: synchronized (lock) 900: { 901: if (isLoggable(Level.CONFIG)) 902: log(Level.CONFIG, message); 903: } 904: } 905: 906: /** 907: * Logs a message with severity level FINE. {@link Level#FINE} is intended for 908: * messages that are relevant for developers using the component generating 909: * log messages. Examples include minor, recoverable failures, or possible 910: * inefficiencies. 911: * 912: * @param message the message text, also used as look-up key if the logger is 913: * localizing messages with a resource bundle. While it is possible 914: * to pass <code>null</code>, this is not recommended, since a 915: * logging message without text is unlikely to be helpful. 916: */ 917: public void fine(String message) 918: { 919: synchronized (lock) 920: { 921: if (isLoggable(Level.FINE)) 922: log(Level.FINE, message); 923: } 924: } 925: 926: /** 927: * Logs a message with severity level FINER. {@link Level#FINER} is intended 928: * for rather detailed tracing, for example entering a method, returning from 929: * a method, or throwing an exception. 930: * 931: * @param message the message text, also used as look-up key if the logger is 932: * localizing messages with a resource bundle. While it is possible 933: * to pass <code>null</code>, this is not recommended, since a 934: * logging message without text is unlikely to be helpful. 935: */ 936: public void finer(String message) 937: { 938: synchronized (lock) 939: { 940: if (isLoggable(Level.FINER)) 941: log(Level.FINER, message); 942: } 943: } 944: 945: /** 946: * Logs a message with severity level FINEST. {@link Level#FINEST} is intended 947: * for highly detailed tracing, for example reaching a certain point inside 948: * the body of a method. 949: * 950: * @param message the message text, also used as look-up key if the logger is 951: * localizing messages with a resource bundle. While it is possible 952: * to pass <code>null</code>, this is not recommended, since a 953: * logging message without text is unlikely to be helpful. 954: */ 955: public void finest(String message) 956: { 957: synchronized (lock) 958: { 959: if (isLoggable(Level.FINEST)) 960: log(Level.FINEST, message); 961: } 962: } 963: 964: /** 965: * Adds a handler to the set of handlers that get notified when a log record 966: * is to be published. 967: * 968: * @param handler the handler to be added. 969: * @throws NullPointerException if <code>handler</code> is <code>null</code>. 970: * @throws SecurityException if this logger is not anonymous, a security 971: * manager exists, and the caller is not granted the permission to 972: * control the logging infrastructure by having 973: * LoggingPermission("control"). Untrusted code can obtain an 974: * anonymous logger through the static factory method 975: * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 976: */ 977: public void addHandler(Handler handler) throws SecurityException 978: { 979: synchronized (lock) 980: { 981: if (handler == null) 982: throw new NullPointerException(); 983: 984: /* 985: * An application is allowed to control an anonymous logger without 986: * having the permission to control the logging infrastructure. 987: */ 988: if (! anonymous) 989: LogManager.getLogManager().checkAccess(); 990: 991: if (! handlerList.contains(handler)) 992: { 993: handlerList.add(handler); 994: handlers = getHandlers(); 995: } 996: } 997: } 998: 999: /** 1000: * Removes a handler from the set of handlers that get notified when a log 1001: * record is to be published. 1002: * 1003: * @param handler the handler to be removed. 1004: * @throws SecurityException if this logger is not anonymous, a security 1005: * manager exists, and the caller is not granted the permission to 1006: * control the logging infrastructure by having 1007: * LoggingPermission("control"). Untrusted code can obtain an 1008: * anonymous logger through the static factory method {@link 1009: * #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 1010: * @throws NullPointerException if <code>handler</code> is <code>null</code>. 1011: */ 1012: public void removeHandler(Handler handler) throws SecurityException 1013: { 1014: synchronized (lock) 1015: { 1016: /* 1017: * An application is allowed to control an anonymous logger without 1018: * having the permission to control the logging infrastructure. 1019: */ 1020: if (! anonymous) 1021: LogManager.getLogManager().checkAccess(); 1022: 1023: if (handler == null) 1024: throw new NullPointerException(); 1025: 1026: handlerList.remove(handler); 1027: handlers = getHandlers(); 1028: } 1029: } 1030: 1031: /** 1032: * Returns the handlers currently registered for this Logger. When a log 1033: * record has been deemed as being loggable, it will be passed to all 1034: * registered handlers for publication. In addition, if the logger uses parent 1035: * handlers (see {@link #getUseParentHandlers() getUseParentHandlers} and 1036: * {@link #setUseParentHandlers(boolean) setUseParentHandlers}, the log 1037: * record will be passed to the parent's handlers. 1038: */ 1039: public Handler[] getHandlers() 1040: { 1041: synchronized (lock) 1042: { 1043: /* 1044: * We cannot return our internal handlers array because we do not have 1045: * any guarantee that the caller would not change the array entries. 1046: */ 1047: return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]); 1048: } 1049: } 1050: 1051: /** 1052: * Returns whether or not this Logger forwards log records to handlers 1053: * registered for its parent loggers. 1054: * 1055: * @return <code>false</code> if this Logger sends log records merely to 1056: * Handlers registered with itself; <code>true</code> if this Logger 1057: * sends log records not only to Handlers registered with itself, but 1058: * also to those Handlers registered with parent loggers. 1059: */ 1060: public boolean getUseParentHandlers() 1061: { 1062: synchronized (lock) 1063: { 1064: return useParentHandlers; 1065: } 1066: } 1067: 1068: /** 1069: * Sets whether or not this Logger forwards log records to handlers registered 1070: * for its parent loggers. 1071: * 1072: * @param useParentHandlers <code>false</code> to let this Logger send log 1073: * records merely to Handlers registered with itself; 1074: * <code>true</code> to let this Logger send log records not only 1075: * to Handlers registered with itself, but also to those Handlers 1076: * registered with parent loggers. 1077: * @throws SecurityException if this logger is not anonymous, a security 1078: * manager exists, and the caller is not granted the permission to 1079: * control the logging infrastructure by having 1080: * LoggingPermission("control"). Untrusted code can obtain an 1081: * anonymous logger through the static factory method 1082: * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 1083: */ 1084: public void setUseParentHandlers(boolean useParentHandlers) 1085: { 1086: synchronized (lock) 1087: { 1088: /* 1089: * An application is allowed to control an anonymous logger without 1090: * having the permission to control the logging infrastructure. 1091: */ 1092: if (! anonymous) 1093: LogManager.getLogManager().checkAccess(); 1094: 1095: this.useParentHandlers = useParentHandlers; 1096: } 1097: } 1098: 1099: /** 1100: * Returns the parent of this logger. By default, the parent is assigned by 1101: * the LogManager by inspecting the logger's name. 1102: * 1103: * @return the parent of this logger (as detemined by the LogManager by 1104: * inspecting logger names), the root logger if no other logger has a 1105: * name which is a prefix of this logger's name, or <code>null</code> 1106: * for the root logger. 1107: */ 1108: public Logger getParent() 1109: { 1110: synchronized (lock) 1111: { 1112: return parent; 1113: } 1114: } 1115: 1116: /** 1117: * Sets the parent of this logger. Usually, applications do not call this 1118: * method directly. Instead, the LogManager will ensure that the tree of 1119: * loggers reflects the hierarchical logger namespace. Basically, this method 1120: * should not be public at all, but the GNU implementation follows the API 1121: * specification. 1122: * 1123: * @throws NullPointerException if <code>parent</code> is <code>null</code>. 1124: * @throws SecurityException if this logger is not anonymous, a security 1125: * manager exists, and the caller is not granted the permission to 1126: * control the logging infrastructure by having 1127: * LoggingPermission("control"). Untrusted code can obtain an 1128: * anonymous logger through the static factory method 1129: * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. 1130: */ 1131: public void setParent(Logger parent) 1132: { 1133: synchronized (lock) 1134: { 1135: if (parent == null) 1136: throw new NullPointerException(); 1137: 1138: if (this == root) 1139: throw new IllegalArgumentException( 1140: "the root logger can only have a null parent"); 1141: 1142: /* 1143: * An application is allowed to control an anonymous logger without 1144: * having the permission to control the logging infrastructure. 1145: */ 1146: if (! anonymous) 1147: LogManager.getLogManager().checkAccess(); 1148: 1149: this.parent = parent; 1150: } 1151: } 1152: 1153: /** 1154: * Gets the StackTraceElement of the first class that is not this class. That 1155: * should be the initial caller of a logging method. 1156: * 1157: * @return caller of the initial logging method or null if unknown. 1158: */ 1159: private StackTraceElement getCallerStackFrame() 1160: { 1161: Throwable t = new Throwable(); 1162: StackTraceElement[] stackTrace = t.getStackTrace(); 1163: int index = 0; 1164: 1165: // skip to stackentries until this class 1166: while (index < stackTrace.length 1167: && ! stackTrace[index].getClassName().equals(getClass().getName())) 1168: index++; 1169: 1170: // skip the stackentries of this class 1171: while (index < stackTrace.length 1172: && stackTrace[index].getClassName().equals(getClass().getName())) 1173: index++; 1174: 1175: return index < stackTrace.length ? stackTrace[index] : null; 1176: } 1177: 1178: /** 1179: * Reset and close handlers attached to this logger. This function is package 1180: * private because it must only be available to the LogManager. 1181: */ 1182: void resetLogger() 1183: { 1184: for (int i = 0; i < handlers.length; i++) 1185: { 1186: handlers[i].close(); 1187: handlerList.remove(handlers[i]); 1188: } 1189: handlers = getHandlers(); 1190: } 1191: }
GNU Classpath (0.97.2) |