Logger.java revision 47f3c98d3c706c02c898cd15fbe6ee19d840c2c6
1/* 2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27package java.util.logging; 28 29import dalvik.system.VMStack; 30import java.lang.ref.WeakReference; 31import java.security.AccessController; 32import java.security.PrivilegedAction; 33import java.util.ArrayList; 34import java.util.Iterator; 35import java.util.Locale; 36import java.util.MissingResourceException; 37import java.util.ResourceBundle; 38import java.util.concurrent.CopyOnWriteArrayList; 39import sun.reflect.CallerSensitive; 40 41/** 42 * A Logger object is used to log messages for a specific 43 * system or application component. Loggers are normally named, 44 * using a hierarchical dot-separated namespace. Logger names 45 * can be arbitrary strings, but they should normally be based on 46 * the package name or class name of the logged component, such 47 * as java.net or javax.swing. In addition it is possible to create 48 * "anonymous" Loggers that are not stored in the Logger namespace. 49 * <p> 50 * Logger objects may be obtained by calls on one of the getLogger 51 * factory methods. These will either create a new Logger or 52 * return a suitable existing Logger. It is important to note that 53 * the Logger returned by one of the {@code getLogger} factory methods 54 * may be garbage collected at any time if a strong reference to the 55 * Logger is not kept. 56 * <p> 57 * Logging messages will be forwarded to registered Handler 58 * objects, which can forward the messages to a variety of 59 * destinations, including consoles, files, OS logs, etc. 60 * <p> 61 * Each Logger keeps track of a "parent" Logger, which is its 62 * nearest existing ancestor in the Logger namespace. 63 * <p> 64 * Each Logger has a "Level" associated with it. This reflects 65 * a minimum Level that this logger cares about. If a Logger's 66 * level is set to <tt>null</tt>, then its effective level is inherited 67 * from its parent, which may in turn obtain it recursively from its 68 * parent, and so on up the tree. 69 * <p> 70 * The log level can be configured based on the properties from the 71 * logging configuration file, as described in the description 72 * of the LogManager class. However it may also be dynamically changed 73 * by calls on the Logger.setLevel method. If a logger's level is 74 * changed the change may also affect child loggers, since any child 75 * logger that has <tt>null</tt> as its level will inherit its 76 * effective level from its parent. 77 * <p> 78 * On each logging call the Logger initially performs a cheap 79 * check of the request level (e.g., SEVERE or FINE) against the 80 * effective log level of the logger. If the request level is 81 * lower than the log level, the logging call returns immediately. 82 * <p> 83 * After passing this initial (cheap) test, the Logger will allocate 84 * a LogRecord to describe the logging message. It will then call a 85 * Filter (if present) to do a more detailed check on whether the 86 * record should be published. If that passes it will then publish 87 * the LogRecord to its output Handlers. By default, loggers also 88 * publish to their parent's Handlers, recursively up the tree. 89 * <p> 90 * Each Logger may have a ResourceBundle name associated with it. 91 * The named bundle will be used for localizing logging messages. 92 * If a Logger does not have its own ResourceBundle name, then 93 * it will inherit the ResourceBundle name from its parent, 94 * recursively up the tree. 95 * <p> 96 * Most of the logger output methods take a "msg" argument. This 97 * msg argument may be either a raw value or a localization key. 98 * During formatting, if the logger has (or inherits) a localization 99 * ResourceBundle and if the ResourceBundle has a mapping for the msg 100 * string, then the msg string is replaced by the localized value. 101 * Otherwise the original msg string is used. Typically, formatters use 102 * java.text.MessageFormat style formatting to format parameters, so 103 * for example a format string "{0} {1}" would format two parameters 104 * as strings. 105 * <p> 106 * When mapping ResourceBundle names to ResourceBundles, the Logger 107 * will first try to use the Thread's ContextClassLoader. If that 108 * is null it will try the SystemClassLoader instead. As a temporary 109 * transition feature in the initial implementation, if the Logger is 110 * unable to locate a ResourceBundle from the ContextClassLoader or 111 * SystemClassLoader the Logger will also search up the class stack 112 * and use successive calling ClassLoaders to try to locate a ResourceBundle. 113 * (This call stack search is to allow containers to transition to 114 * using ContextClassLoaders and is likely to be removed in future 115 * versions.) 116 * <p> 117 * Formatting (including localization) is the responsibility of 118 * the output Handler, which will typically call a Formatter. 119 * <p> 120 * Note that formatting need not occur synchronously. It may be delayed 121 * until a LogRecord is actually written to an external sink. 122 * <p> 123 * The logging methods are grouped in five main categories: 124 * <ul> 125 * <li><p> 126 * There are a set of "log" methods that take a log level, a message 127 * string, and optionally some parameters to the message string. 128 * <li><p> 129 * There are a set of "logp" methods (for "log precise") that are 130 * like the "log" methods, but also take an explicit source class name 131 * and method name. 132 * <li><p> 133 * There are a set of "logrb" method (for "log with resource bundle") 134 * that are like the "logp" method, but also take an explicit resource 135 * bundle name for use in localizing the log message. 136 * <li><p> 137 * There are convenience methods for tracing method entries (the 138 * "entering" methods), method returns (the "exiting" methods) and 139 * throwing exceptions (the "throwing" methods). 140 * <li><p> 141 * Finally, there are a set of convenience methods for use in the 142 * very simplest cases, when a developer simply wants to log a 143 * simple string at a given log level. These methods are named 144 * after the standard Level names ("severe", "warning", "info", etc.) 145 * and take a single argument, a message string. 146 * </ul> 147 * <p> 148 * For the methods that do not take an explicit source name and 149 * method name, the Logging framework will make a "best effort" 150 * to determine which class and method called into the logging method. 151 * However, it is important to realize that this automatically inferred 152 * information may only be approximate (or may even be quite wrong!). 153 * Virtual machines are allowed to do extensive optimizations when 154 * JITing and may entirely remove stack frames, making it impossible 155 * to reliably locate the calling class and method. 156 * <P> 157 * All methods on Logger are multi-thread safe. 158 * <p> 159 * <b>Subclassing Information:</b> Note that a LogManager class may 160 * provide its own implementation of named Loggers for any point in 161 * the namespace. Therefore, any subclasses of Logger (unless they 162 * are implemented in conjunction with a new LogManager class) should 163 * take care to obtain a Logger instance from the LogManager class and 164 * should delegate operations such as "isLoggable" and "log(LogRecord)" 165 * to that instance. Note that in order to intercept all logging 166 * output, subclasses need only override the log(LogRecord) method. 167 * All the other logging methods are implemented as calls on this 168 * log(LogRecord) method. 169 * 170 * @since 1.4 171 */ 172 173 174public class Logger { 175 private static final Handler emptyHandlers[] = new Handler[0]; 176 private static final int offValue = Level.OFF.intValue(); 177 private LogManager manager; 178 private String name; 179 private final CopyOnWriteArrayList<Handler> handlers = 180 new CopyOnWriteArrayList<>(); 181 private String resourceBundleName; 182 private volatile boolean useParentHandlers = true; 183 private volatile Filter filter; 184 private boolean anonymous; 185 186 private ResourceBundle catalog; // Cached resource bundle 187 private String catalogName; // name associated with catalog 188 private Locale catalogLocale; // locale associated with catalog 189 190 // The fields relating to parent-child relationships and levels 191 // are managed under a separate lock, the treeLock. 192 private static Object treeLock = new Object(); 193 // We keep weak references from parents to children, but strong 194 // references from children to parents. 195 private volatile Logger parent; // our nearest parent. 196 private ArrayList<LogManager.LoggerWeakRef> kids; // WeakReferences to loggers that have us as parent 197 private volatile Level levelObject; 198 private volatile int levelValue; // current effective level value 199 private WeakReference<ClassLoader> callersClassLoaderRef; 200 201 /** 202 * GLOBAL_LOGGER_NAME is a name for the global logger. 203 * 204 * @since 1.6 205 */ 206 public static final String GLOBAL_LOGGER_NAME = "global"; 207 208 /** 209 * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME. 210 * 211 * @return global logger object 212 * @since 1.7 213 */ 214 public static final Logger getGlobal() { 215 return global; 216 } 217 218 /** 219 * The "global" Logger object is provided as a convenience to developers 220 * who are making casual use of the Logging package. Developers 221 * who are making serious use of the logging package (for example 222 * in products) should create and use their own Logger objects, 223 * with appropriate names, so that logging can be controlled on a 224 * suitable per-Logger granularity. Developers also need to keep a 225 * strong reference to their Logger objects to prevent them from 226 * being garbage collected. 227 * <p> 228 * @deprecated Initialization of this field is prone to deadlocks. 229 * The field must be initialized by the Logger class initialization 230 * which may cause deadlocks with the LogManager class initialization. 231 * In such cases two class initialization wait for each other to complete. 232 * The preferred way to get the global logger object is via the call 233 * <code>Logger.getGlobal()</code>. 234 * For compatibility with old JDK versions where the 235 * <code>Logger.getGlobal()</code> is not available use the call 236 * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code> 237 * or <code>Logger.getLogger("global")</code>. 238 */ 239 @Deprecated 240 public static final Logger global = new Logger(GLOBAL_LOGGER_NAME); 241 242 /** 243 * Protected method to construct a logger for a named subsystem. 244 * <p> 245 * The logger will be initially configured with a null Level 246 * and with useParentHandlers set to true. 247 * 248 * @param name A name for the logger. This should 249 * be a dot-separated name and should normally 250 * be based on the package name or class name 251 * of the subsystem, such as java.net 252 * or javax.swing. It may be null for anonymous Loggers. 253 * @param resourceBundleName name of ResourceBundle to be used for localizing 254 * messages for this logger. May be null if none 255 * of the messages require localization. 256 * @throws MissingResourceException if the resourceBundleName is non-null and 257 * no corresponding resource can be found. 258 */ 259 protected Logger(String name, String resourceBundleName) { 260 this(name, resourceBundleName, null); 261 } 262 263 Logger(String name, String resourceBundleName, Class<?> caller) { 264 this.manager = LogManager.getLogManager(); 265 setupResourceInfo(resourceBundleName, caller); 266 this.name = name; 267 levelValue = Level.INFO.intValue(); 268 } 269 270 private void setCallersClassLoaderRef(Class<?> caller) { 271 ClassLoader callersClassLoader = ((caller != null) 272 ? caller.getClassLoader() 273 : null); 274 if (callersClassLoader != null) { 275 this.callersClassLoaderRef = new WeakReference(callersClassLoader); 276 } 277 } 278 279 private ClassLoader getCallersClassLoader() { 280 return (callersClassLoaderRef != null) 281 ? callersClassLoaderRef.get() 282 : null; 283 } 284 285 // This constructor is used only to create the global Logger. 286 // It is needed to break a cyclic dependence between the LogManager 287 // and Logger static initializers causing deadlocks. 288 private Logger(String name) { 289 // The manager field is not initialized here. 290 this.name = name; 291 levelValue = Level.INFO.intValue(); 292 } 293 294 // It is called from the LogManager.<clinit> to complete 295 // initialization of the global Logger. 296 void setLogManager(LogManager manager) { 297 this.manager = manager; 298 } 299 300 private void checkPermission() throws SecurityException { 301 if (!anonymous) { 302 if (manager == null) { 303 // Complete initialization of the global Logger. 304 manager = LogManager.getLogManager(); 305 } 306 manager.checkPermission(); 307 } 308 } 309 310 // Until all JDK code converted to call sun.util.logging.PlatformLogger 311 // (see 7054233), we need to determine if Logger.getLogger is to add 312 // a system logger or user logger. 313 // 314 // As an interim solution, if the immediate caller whose caller loader is 315 // null, we assume it's a system logger and add it to the system context. 316 // These system loggers only set the resource bundle to the given 317 // resource bundle name (rather than the default system resource bundle). 318 private static class LoggerHelper { 319 static boolean disableCallerCheck = 320 getBooleanProperty("sun.util.logging.disableCallerCheck"); 321 322 // workaround to turn on the old behavior for resource bundle search 323 static boolean allowStackWalkSearch = 324 getBooleanProperty("jdk.logging.allowStackWalkSearch"); 325 private static boolean getBooleanProperty(final String key) { 326 String s = AccessController.doPrivileged(new PrivilegedAction<String>() { 327 public String run() { 328 return System.getProperty(key); 329 } 330 }); 331 return Boolean.valueOf(s); 332 } 333 } 334 335 private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 336 LogManager manager = LogManager.getLogManager(); 337 SecurityManager sm = System.getSecurityManager(); 338 if (sm != null && !LoggerHelper.disableCallerCheck) { 339 if (caller.getClassLoader() == null) { 340 return manager.demandSystemLogger(name, resourceBundleName); 341 } 342 } 343 return manager.demandLogger(name, resourceBundleName, caller); 344 // ends up calling new Logger(name, resourceBundleName, caller) 345 // iff the logger doesn't exist already 346 } 347 348 /** 349 * Find or create a logger for a named subsystem. If a logger has 350 * already been created with the given name it is returned. Otherwise 351 * a new logger is created. 352 * <p> 353 * If a new logger is created its log level will be configured 354 * based on the LogManager configuration and it will configured 355 * to also send logging output to its parent's Handlers. It will 356 * be registered in the LogManager global namespace. 357 * <p> 358 * Note: The LogManager may only retain a weak reference to the newly 359 * created Logger. It is important to understand that a previously 360 * created Logger with the given name may be garbage collected at any 361 * time if there is no strong reference to the Logger. In particular, 362 * this means that two back-to-back calls like 363 * {@code getLogger("MyLogger").log(...)} may use different Logger 364 * objects named "MyLogger" if there is no strong reference to the 365 * Logger named "MyLogger" elsewhere in the program. 366 * 367 * @param name A name for the logger. This should 368 * be a dot-separated name and should normally 369 * be based on the package name or class name 370 * of the subsystem, such as java.net 371 * or javax.swing 372 * @return a suitable Logger 373 * @throws NullPointerException if the name is null. 374 */ 375 376 // Synchronization is not required here. All synchronization for 377 // adding a new Logger object is handled by LogManager.addLogger(). 378 @CallerSensitive 379 public static Logger getLogger(String name) { 380 // This method is intentionally not a wrapper around a call 381 // to getLogger(name, resourceBundleName). If it were then 382 // this sequence: 383 // 384 // getLogger("Foo", "resourceBundleForFoo"); 385 // getLogger("Foo"); 386 // 387 // would throw an IllegalArgumentException in the second call 388 // because the wrapper would result in an attempt to replace 389 // the existing "resourceBundleForFoo" with null. 390 // 391 // Android-changed: Use VMStack.getStackClass1. 392 return demandLogger(name, null, VMStack.getStackClass1()); 393 } 394 395 /** 396 * Find or create a logger for a named subsystem. If a logger has 397 * already been created with the given name it is returned. Otherwise 398 * a new logger is created. 399 * <p> 400 * If a new logger is created its log level will be configured 401 * based on the LogManager and it will configured to also send logging 402 * output to its parent's Handlers. It will be registered in 403 * the LogManager global namespace. 404 * <p> 405 * Note: The LogManager may only retain a weak reference to the newly 406 * created Logger. It is important to understand that a previously 407 * created Logger with the given name may be garbage collected at any 408 * time if there is no strong reference to the Logger. In particular, 409 * this means that two back-to-back calls like 410 * {@code getLogger("MyLogger", ...).log(...)} may use different Logger 411 * objects named "MyLogger" if there is no strong reference to the 412 * Logger named "MyLogger" elsewhere in the program. 413 * <p> 414 * If the named Logger already exists and does not yet have a 415 * localization resource bundle then the given resource bundle 416 * name is used. If the named Logger already exists and has 417 * a different resource bundle name then an IllegalArgumentException 418 * is thrown. 419 * <p> 420 * @param name A name for the logger. This should 421 * be a dot-separated name and should normally 422 * be based on the package name or class name 423 * of the subsystem, such as java.net 424 * or javax.swing 425 * @param resourceBundleName name of ResourceBundle to be used for localizing 426 * messages for this logger. May be <CODE>null</CODE> if none of 427 * the messages require localization. 428 * @return a suitable Logger 429 * @throws MissingResourceException if the resourceBundleName is non-null and 430 * no corresponding resource can be found. 431 * @throws IllegalArgumentException if the Logger already exists and uses 432 * a different resource bundle name. 433 * @throws NullPointerException if the name is null. 434 */ 435 436 // Synchronization is not required here. All synchronization for 437 // adding a new Logger object is handled by LogManager.addLogger(). 438 @CallerSensitive 439 public static Logger getLogger(String name, String resourceBundleName) { 440 // Android-changed: Use VMStack.getStackClass1. 441 Class<?> callerClass = VMStack.getStackClass1(); 442 Logger result = demandLogger(name, resourceBundleName, callerClass); 443 444 if (result.resourceBundleName == null) { 445 // We haven't set a bundle name yet on the Logger, so it's ok to proceed. 446 447 // We have to set the callers ClassLoader here in case demandLogger 448 // above found a previously created Logger. This can happen, for 449 // example, if Logger.getLogger(name) is called and subsequently 450 // Logger.getLogger(name, resourceBundleName) is called. In this case 451 // we won't necessarily have the correct classloader saved away, so 452 // we need to set it here, too. 453 454 // Note: we may get a MissingResourceException here. 455 result.setupResourceInfo(resourceBundleName, callerClass); 456 } else if (!result.resourceBundleName.equals(resourceBundleName)) { 457 // We already had a bundle name on the Logger and we're trying 458 // to change it here which is not allowed. 459 throw new IllegalArgumentException(result.resourceBundleName + 460 " != " + resourceBundleName); 461 } 462 return result; 463 } 464 465 // package-private 466 // Add a platform logger to the system context. 467 // i.e. caller of sun.util.logging.PlatformLogger.getLogger 468 static Logger getPlatformLogger(String name) { 469 LogManager manager = LogManager.getLogManager(); 470 471 // all loggers in the system context will default to 472 // the system logger's resource bundle 473 Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME); 474 return result; 475 } 476 477 /** 478 * Create an anonymous Logger. The newly created Logger is not 479 * registered in the LogManager namespace. There will be no 480 * access checks on updates to the logger. 481 * <p> 482 * This factory method is primarily intended for use from applets. 483 * Because the resulting Logger is anonymous it can be kept private 484 * by the creating class. This removes the need for normal security 485 * checks, which in turn allows untrusted applet code to update 486 * the control state of the Logger. For example an applet can do 487 * a setLevel or an addHandler on an anonymous Logger. 488 * <p> 489 * Even although the new logger is anonymous, it is configured 490 * to have the root logger ("") as its parent. This means that 491 * by default it inherits its effective level and handlers 492 * from the root logger. 493 * <p> 494 * 495 * @return a newly created private Logger 496 */ 497 public static Logger getAnonymousLogger() { 498 return getAnonymousLogger(null); 499 } 500 501 /** 502 * Create an anonymous Logger. The newly created Logger is not 503 * registered in the LogManager namespace. There will be no 504 * access checks on updates to the logger. 505 * <p> 506 * This factory method is primarily intended for use from applets. 507 * Because the resulting Logger is anonymous it can be kept private 508 * by the creating class. This removes the need for normal security 509 * checks, which in turn allows untrusted applet code to update 510 * the control state of the Logger. For example an applet can do 511 * a setLevel or an addHandler on an anonymous Logger. 512 * <p> 513 * Even although the new logger is anonymous, it is configured 514 * to have the root logger ("") as its parent. This means that 515 * by default it inherits its effective level and handlers 516 * from the root logger. 517 * <p> 518 * @param resourceBundleName name of ResourceBundle to be used for localizing 519 * messages for this logger. 520 * May be null if none of the messages require localization. 521 * @return a newly created private Logger 522 * @throws MissingResourceException if the resourceBundleName is non-null and 523 * no corresponding resource can be found. 524 */ 525 526 // Synchronization is not required here. All synchronization for 527 // adding a new anonymous Logger object is handled by doSetParent(). 528 @CallerSensitive 529 public static Logger getAnonymousLogger(String resourceBundleName) { 530 LogManager manager = LogManager.getLogManager(); 531 // cleanup some Loggers that have been GC'ed 532 manager.drainLoggerRefQueueBounded(); 533 // Android-changed: Use VMStack.getStackClass1. 534 Logger result = new Logger(null, resourceBundleName, 535 VMStack.getStackClass1()); 536 result.anonymous = true; 537 Logger root = manager.getLogger(""); 538 result.doSetParent(root); 539 return result; 540 } 541 542 /** 543 * Retrieve the localization resource bundle for this 544 * logger for the current default locale. Note that if 545 * the result is null, then the Logger will use a resource 546 * bundle inherited from its parent. 547 * 548 * @return localization bundle (may be null) 549 */ 550 public ResourceBundle getResourceBundle() { 551 return findResourceBundle(getResourceBundleName(), true); 552 } 553 554 /** 555 * Retrieve the localization resource bundle name for this 556 * logger. Note that if the result is null, then the Logger 557 * will use a resource bundle name inherited from its parent. 558 * 559 * @return localization bundle name (may be null) 560 */ 561 public String getResourceBundleName() { 562 return resourceBundleName; 563 } 564 565 /** 566 * Set a filter to control output on this Logger. 567 * <P> 568 * After passing the initial "level" check, the Logger will 569 * call this Filter to check if a log record should really 570 * be published. 571 * 572 * @param newFilter a filter object (may be null) 573 * @exception SecurityException if a security manager exists and if 574 * the caller does not have LoggingPermission("control"). 575 */ 576 public void setFilter(Filter newFilter) throws SecurityException { 577 checkPermission(); 578 filter = newFilter; 579 } 580 581 /** 582 * Get the current filter for this Logger. 583 * 584 * @return a filter object (may be null) 585 */ 586 public Filter getFilter() { 587 return filter; 588 } 589 590 /** 591 * Log a LogRecord. 592 * <p> 593 * All the other logging methods in this class call through 594 * this method to actually perform any logging. Subclasses can 595 * override this single method to capture all log activity. 596 * 597 * @param record the LogRecord to be published 598 */ 599 public void log(LogRecord record) { 600 if (record.getLevel().intValue() < levelValue || levelValue == offValue) { 601 return; 602 } 603 Filter theFilter = filter; 604 if (theFilter != null && !theFilter.isLoggable(record)) { 605 return; 606 } 607 608 // Post the LogRecord to all our Handlers, and then to 609 // our parents' handlers, all the way up the tree. 610 611 Logger logger = this; 612 while (logger != null) { 613 for (Handler handler : logger.getHandlers()) { 614 handler.publish(record); 615 } 616 617 if (!logger.getUseParentHandlers()) { 618 break; 619 } 620 621 logger = logger.getParent(); 622 } 623 } 624 625 // private support method for logging. 626 // We fill in the logger name, resource bundle name, and 627 // resource bundle and then call "void log(LogRecord)". 628 private void doLog(LogRecord lr) { 629 lr.setLoggerName(name); 630 String ebname = getEffectiveResourceBundleName(); 631 if (ebname != null && !ebname.equals(SYSTEM_LOGGER_RB_NAME)) { 632 lr.setResourceBundleName(ebname); 633 lr.setResourceBundle(findResourceBundle(ebname, true)); 634 } 635 log(lr); 636 } 637 638 639 //================================================================ 640 // Start of convenience methods WITHOUT className and methodName 641 //================================================================ 642 643 /** 644 * Log a message, with no arguments. 645 * <p> 646 * If the logger is currently enabled for the given message 647 * level then the given message is forwarded to all the 648 * registered output Handler objects. 649 * <p> 650 * @param level One of the message level identifiers, e.g., SEVERE 651 * @param msg The string message (or a key in the message catalog) 652 */ 653 public void log(Level level, String msg) { 654 if (level.intValue() < levelValue || levelValue == offValue) { 655 return; 656 } 657 LogRecord lr = new LogRecord(level, msg); 658 doLog(lr); 659 } 660 661 /** 662 * Log a message, with one object parameter. 663 * <p> 664 * If the logger is currently enabled for the given message 665 * level then a corresponding LogRecord is created and forwarded 666 * to all the registered output Handler objects. 667 * <p> 668 * @param level One of the message level identifiers, e.g., SEVERE 669 * @param msg The string message (or a key in the message catalog) 670 * @param param1 parameter to the message 671 */ 672 public void log(Level level, String msg, Object param1) { 673 if (level.intValue() < levelValue || levelValue == offValue) { 674 return; 675 } 676 LogRecord lr = new LogRecord(level, msg); 677 Object params[] = { param1 }; 678 lr.setParameters(params); 679 doLog(lr); 680 } 681 682 /** 683 * Log a message, with an array of object arguments. 684 * <p> 685 * If the logger is currently enabled for the given message 686 * level then a corresponding LogRecord is created and forwarded 687 * to all the registered output Handler objects. 688 * <p> 689 * @param level One of the message level identifiers, e.g., SEVERE 690 * @param msg The string message (or a key in the message catalog) 691 * @param params array of parameters to the message 692 */ 693 public void log(Level level, String msg, Object params[]) { 694 if (level.intValue() < levelValue || levelValue == offValue) { 695 return; 696 } 697 LogRecord lr = new LogRecord(level, msg); 698 lr.setParameters(params); 699 doLog(lr); 700 } 701 702 /** 703 * Log a message, with associated Throwable information. 704 * <p> 705 * If the logger is currently enabled for the given message 706 * level then the given arguments are stored in a LogRecord 707 * which is forwarded to all registered output handlers. 708 * <p> 709 * Note that the thrown argument is stored in the LogRecord thrown 710 * property, rather than the LogRecord parameters property. Thus is it 711 * processed specially by output Formatters and is not treated 712 * as a formatting parameter to the LogRecord message property. 713 * <p> 714 * @param level One of the message level identifiers, e.g., SEVERE 715 * @param msg The string message (or a key in the message catalog) 716 * @param thrown Throwable associated with log message. 717 */ 718 public void log(Level level, String msg, Throwable thrown) { 719 if (level.intValue() < levelValue || levelValue == offValue) { 720 return; 721 } 722 LogRecord lr = new LogRecord(level, msg); 723 lr.setThrown(thrown); 724 doLog(lr); 725 } 726 727 //================================================================ 728 // Start of convenience methods WITH className and methodName 729 //================================================================ 730 731 /** 732 * Log a message, specifying source class and method, 733 * with no arguments. 734 * <p> 735 * If the logger is currently enabled for the given message 736 * level then the given message is forwarded to all the 737 * registered output Handler objects. 738 * <p> 739 * @param level One of the message level identifiers, e.g., SEVERE 740 * @param sourceClass name of class that issued the logging request 741 * @param sourceMethod name of method that issued the logging request 742 * @param msg The string message (or a key in the message catalog) 743 */ 744 public void logp(Level level, String sourceClass, String sourceMethod, String msg) { 745 if (level.intValue() < levelValue || levelValue == offValue) { 746 return; 747 } 748 LogRecord lr = new LogRecord(level, msg); 749 lr.setSourceClassName(sourceClass); 750 lr.setSourceMethodName(sourceMethod); 751 doLog(lr); 752 } 753 754 /** 755 * Log a message, specifying source class and method, 756 * with a single object parameter to the log message. 757 * <p> 758 * If the logger is currently enabled for the given message 759 * level then a corresponding LogRecord is created and forwarded 760 * to all the registered output Handler objects. 761 * <p> 762 * @param level One of the message level identifiers, e.g., SEVERE 763 * @param sourceClass name of class that issued the logging request 764 * @param sourceMethod name of method that issued the logging request 765 * @param msg The string message (or a key in the message catalog) 766 * @param param1 Parameter to the log message. 767 */ 768 public void logp(Level level, String sourceClass, String sourceMethod, 769 String msg, Object param1) { 770 if (level.intValue() < levelValue || levelValue == offValue) { 771 return; 772 } 773 LogRecord lr = new LogRecord(level, msg); 774 lr.setSourceClassName(sourceClass); 775 lr.setSourceMethodName(sourceMethod); 776 Object params[] = { param1 }; 777 lr.setParameters(params); 778 doLog(lr); 779 } 780 781 /** 782 * Log a message, specifying source class and method, 783 * with an array of object arguments. 784 * <p> 785 * If the logger is currently enabled for the given message 786 * level then a corresponding LogRecord is created and forwarded 787 * to all the registered output Handler objects. 788 * <p> 789 * @param level One of the message level identifiers, e.g., SEVERE 790 * @param sourceClass name of class that issued the logging request 791 * @param sourceMethod name of method that issued the logging request 792 * @param msg The string message (or a key in the message catalog) 793 * @param params Array of parameters to the message 794 */ 795 public void logp(Level level, String sourceClass, String sourceMethod, 796 String msg, Object params[]) { 797 if (level.intValue() < levelValue || levelValue == offValue) { 798 return; 799 } 800 LogRecord lr = new LogRecord(level, msg); 801 lr.setSourceClassName(sourceClass); 802 lr.setSourceMethodName(sourceMethod); 803 lr.setParameters(params); 804 doLog(lr); 805 } 806 807 /** 808 * Log a message, specifying source class and method, 809 * with associated Throwable information. 810 * <p> 811 * If the logger is currently enabled for the given message 812 * level then the given arguments are stored in a LogRecord 813 * which is forwarded to all registered output handlers. 814 * <p> 815 * Note that the thrown argument is stored in the LogRecord thrown 816 * property, rather than the LogRecord parameters property. Thus is it 817 * processed specially by output Formatters and is not treated 818 * as a formatting parameter to the LogRecord message property. 819 * <p> 820 * @param level One of the message level identifiers, e.g., SEVERE 821 * @param sourceClass name of class that issued the logging request 822 * @param sourceMethod name of method that issued the logging request 823 * @param msg The string message (or a key in the message catalog) 824 * @param thrown Throwable associated with log message. 825 */ 826 public void logp(Level level, String sourceClass, String sourceMethod, 827 String msg, Throwable thrown) { 828 if (level.intValue() < levelValue || levelValue == offValue) { 829 return; 830 } 831 LogRecord lr = new LogRecord(level, msg); 832 lr.setSourceClassName(sourceClass); 833 lr.setSourceMethodName(sourceMethod); 834 lr.setThrown(thrown); 835 doLog(lr); 836 } 837 838 839 //========================================================================= 840 // Start of convenience methods WITH className, methodName and bundle name. 841 //========================================================================= 842 843 // Private support method for logging for "logrb" methods. 844 // We fill in the logger name, resource bundle name, and 845 // resource bundle and then call "void log(LogRecord)". 846 private void doLog(LogRecord lr, String rbname) { 847 lr.setLoggerName(name); 848 if (rbname != null) { 849 lr.setResourceBundleName(rbname); 850 lr.setResourceBundle(findResourceBundle(rbname, false)); 851 } 852 log(lr); 853 } 854 855 /** 856 * Log a message, specifying source class, method, and resource bundle name 857 * with no arguments. 858 * <p> 859 * If the logger is currently enabled for the given message 860 * level then the given message is forwarded to all the 861 * registered output Handler objects. 862 * <p> 863 * The msg string is localized using the named resource bundle. If the 864 * resource bundle name is null, or an empty String or invalid 865 * then the msg string is not localized. 866 * <p> 867 * @param level One of the message level identifiers, e.g., SEVERE 868 * @param sourceClass name of class that issued the logging request 869 * @param sourceMethod name of method that issued the logging request 870 * @param bundleName name of resource bundle to localize msg, 871 * can be null 872 * @param msg The string message (or a key in the message catalog) 873 */ 874 public void logrb(Level level, String sourceClass, String sourceMethod, 875 String bundleName, String msg) { 876 if (level.intValue() < levelValue || levelValue == offValue) { 877 return; 878 } 879 LogRecord lr = new LogRecord(level, msg); 880 lr.setSourceClassName(sourceClass); 881 lr.setSourceMethodName(sourceMethod); 882 doLog(lr, bundleName); 883 } 884 885 /** 886 * Log a message, specifying source class, method, and resource bundle name, 887 * with a single object parameter to the log message. 888 * <p> 889 * If the logger is currently enabled for the given message 890 * level then a corresponding LogRecord is created and forwarded 891 * to all the registered output Handler objects. 892 * <p> 893 * The msg string is localized using the named resource bundle. If the 894 * resource bundle name is null, or an empty String or invalid 895 * then the msg string is not localized. 896 * <p> 897 * @param level One of the message level identifiers, e.g., SEVERE 898 * @param sourceClass name of class that issued the logging request 899 * @param sourceMethod name of method that issued the logging request 900 * @param bundleName name of resource bundle to localize msg, 901 * can be null 902 * @param msg The string message (or a key in the message catalog) 903 * @param param1 Parameter to the log message. 904 */ 905 public void logrb(Level level, String sourceClass, String sourceMethod, 906 String bundleName, String msg, Object param1) { 907 if (level.intValue() < levelValue || levelValue == offValue) { 908 return; 909 } 910 LogRecord lr = new LogRecord(level, msg); 911 lr.setSourceClassName(sourceClass); 912 lr.setSourceMethodName(sourceMethod); 913 Object params[] = { param1 }; 914 lr.setParameters(params); 915 doLog(lr, bundleName); 916 } 917 918 /** 919 * Log a message, specifying source class, method, and resource bundle name, 920 * with an array of object arguments. 921 * <p> 922 * If the logger is currently enabled for the given message 923 * level then a corresponding LogRecord is created and forwarded 924 * to all the registered output Handler objects. 925 * <p> 926 * The msg string is localized using the named resource bundle. If the 927 * resource bundle name is null, or an empty String or invalid 928 * then the msg string is not localized. 929 * <p> 930 * @param level One of the message level identifiers, e.g., SEVERE 931 * @param sourceClass name of class that issued the logging request 932 * @param sourceMethod name of method that issued the logging request 933 * @param bundleName name of resource bundle to localize msg, 934 * can be null. 935 * @param msg The string message (or a key in the message catalog) 936 * @param params Array of parameters to the message 937 */ 938 public void logrb(Level level, String sourceClass, String sourceMethod, 939 String bundleName, String msg, Object params[]) { 940 if (level.intValue() < levelValue || levelValue == offValue) { 941 return; 942 } 943 LogRecord lr = new LogRecord(level, msg); 944 lr.setSourceClassName(sourceClass); 945 lr.setSourceMethodName(sourceMethod); 946 lr.setParameters(params); 947 doLog(lr, bundleName); 948 } 949 950 /** 951 * Log a message, specifying source class, method, and resource bundle name, 952 * with associated Throwable information. 953 * <p> 954 * If the logger is currently enabled for the given message 955 * level then the given arguments are stored in a LogRecord 956 * which is forwarded to all registered output handlers. 957 * <p> 958 * The msg string is localized using the named resource bundle. If the 959 * resource bundle name is null, or an empty String or invalid 960 * then the msg string is not localized. 961 * <p> 962 * Note that the thrown argument is stored in the LogRecord thrown 963 * property, rather than the LogRecord parameters property. Thus is it 964 * processed specially by output Formatters and is not treated 965 * as a formatting parameter to the LogRecord message property. 966 * <p> 967 * @param level One of the message level identifiers, e.g., SEVERE 968 * @param sourceClass name of class that issued the logging request 969 * @param sourceMethod name of method that issued the logging request 970 * @param bundleName name of resource bundle to localize msg, 971 * can be null 972 * @param msg The string message (or a key in the message catalog) 973 * @param thrown Throwable associated with log message. 974 */ 975 public void logrb(Level level, String sourceClass, String sourceMethod, 976 String bundleName, String msg, Throwable thrown) { 977 if (level.intValue() < levelValue || levelValue == offValue) { 978 return; 979 } 980 LogRecord lr = new LogRecord(level, msg); 981 lr.setSourceClassName(sourceClass); 982 lr.setSourceMethodName(sourceMethod); 983 lr.setThrown(thrown); 984 doLog(lr, bundleName); 985 } 986 987 988 //====================================================================== 989 // Start of convenience methods for logging method entries and returns. 990 //====================================================================== 991 992 /** 993 * Log a method entry. 994 * <p> 995 * This is a convenience method that can be used to log entry 996 * to a method. A LogRecord with message "ENTRY", log level 997 * FINER, and the given sourceMethod and sourceClass is logged. 998 * <p> 999 * @param sourceClass name of class that issued the logging request 1000 * @param sourceMethod name of method that is being entered 1001 */ 1002 public void entering(String sourceClass, String sourceMethod) { 1003 if (Level.FINER.intValue() < levelValue) { 1004 return; 1005 } 1006 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); 1007 } 1008 1009 /** 1010 * Log a method entry, with one parameter. 1011 * <p> 1012 * This is a convenience method that can be used to log entry 1013 * to a method. A LogRecord with message "ENTRY {0}", log level 1014 * FINER, and the given sourceMethod, sourceClass, and parameter 1015 * is logged. 1016 * <p> 1017 * @param sourceClass name of class that issued the logging request 1018 * @param sourceMethod name of method that is being entered 1019 * @param param1 parameter to the method being entered 1020 */ 1021 public void entering(String sourceClass, String sourceMethod, Object param1) { 1022 if (Level.FINER.intValue() < levelValue) { 1023 return; 1024 } 1025 Object params[] = { param1 }; 1026 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params); 1027 } 1028 1029 /** 1030 * Log a method entry, with an array of parameters. 1031 * <p> 1032 * This is a convenience method that can be used to log entry 1033 * to a method. A LogRecord with message "ENTRY" (followed by a 1034 * format {N} indicator for each entry in the parameter array), 1035 * log level FINER, and the given sourceMethod, sourceClass, and 1036 * parameters is logged. 1037 * <p> 1038 * @param sourceClass name of class that issued the logging request 1039 * @param sourceMethod name of method that is being entered 1040 * @param params array of parameters to the method being entered 1041 */ 1042 public void entering(String sourceClass, String sourceMethod, Object params[]) { 1043 if (Level.FINER.intValue() < levelValue) { 1044 return; 1045 } 1046 String msg = "ENTRY"; 1047 if (params == null ) { 1048 logp(Level.FINER, sourceClass, sourceMethod, msg); 1049 return; 1050 } 1051 for (int i = 0; i < params.length; i++) { 1052 msg = msg + " {" + i + "}"; 1053 } 1054 logp(Level.FINER, sourceClass, sourceMethod, msg, params); 1055 } 1056 1057 /** 1058 * Log a method return. 1059 * <p> 1060 * This is a convenience method that can be used to log returning 1061 * from a method. A LogRecord with message "RETURN", log level 1062 * FINER, and the given sourceMethod and sourceClass is logged. 1063 * <p> 1064 * @param sourceClass name of class that issued the logging request 1065 * @param sourceMethod name of the method 1066 */ 1067 public void exiting(String sourceClass, String sourceMethod) { 1068 if (Level.FINER.intValue() < levelValue) { 1069 return; 1070 } 1071 logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); 1072 } 1073 1074 1075 /** 1076 * Log a method return, with result object. 1077 * <p> 1078 * This is a convenience method that can be used to log returning 1079 * from a method. A LogRecord with message "RETURN {0}", log level 1080 * FINER, and the gives sourceMethod, sourceClass, and result 1081 * object is logged. 1082 * <p> 1083 * @param sourceClass name of class that issued the logging request 1084 * @param sourceMethod name of the method 1085 * @param result Object that is being returned 1086 */ 1087 public void exiting(String sourceClass, String sourceMethod, Object result) { 1088 if (Level.FINER.intValue() < levelValue) { 1089 return; 1090 } 1091 Object params[] = { result }; 1092 logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); 1093 } 1094 1095 /** 1096 * Log throwing an exception. 1097 * <p> 1098 * This is a convenience method to log that a method is 1099 * terminating by throwing an exception. The logging is done 1100 * using the FINER level. 1101 * <p> 1102 * If the logger is currently enabled for the given message 1103 * level then the given arguments are stored in a LogRecord 1104 * which is forwarded to all registered output handlers. The 1105 * LogRecord's message is set to "THROW". 1106 * <p> 1107 * Note that the thrown argument is stored in the LogRecord thrown 1108 * property, rather than the LogRecord parameters property. Thus is it 1109 * processed specially by output Formatters and is not treated 1110 * as a formatting parameter to the LogRecord message property. 1111 * <p> 1112 * @param sourceClass name of class that issued the logging request 1113 * @param sourceMethod name of the method. 1114 * @param thrown The Throwable that is being thrown. 1115 */ 1116 public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { 1117 if (Level.FINER.intValue() < levelValue || levelValue == offValue ) { 1118 return; 1119 } 1120 LogRecord lr = new LogRecord(Level.FINER, "THROW"); 1121 lr.setSourceClassName(sourceClass); 1122 lr.setSourceMethodName(sourceMethod); 1123 lr.setThrown(thrown); 1124 doLog(lr); 1125 } 1126 1127 //======================================================================= 1128 // Start of simple convenience methods using level names as method names 1129 //======================================================================= 1130 1131 /** 1132 * Log a SEVERE message. 1133 * <p> 1134 * If the logger is currently enabled for the SEVERE message 1135 * level then the given message is forwarded to all the 1136 * registered output Handler objects. 1137 * <p> 1138 * @param msg The string message (or a key in the message catalog) 1139 */ 1140 public void severe(String msg) { 1141 if (Level.SEVERE.intValue() < levelValue) { 1142 return; 1143 } 1144 log(Level.SEVERE, msg); 1145 } 1146 1147 /** 1148 * Log a WARNING message. 1149 * <p> 1150 * If the logger is currently enabled for the WARNING message 1151 * level then the given message is forwarded to all the 1152 * registered output Handler objects. 1153 * <p> 1154 * @param msg The string message (or a key in the message catalog) 1155 */ 1156 public void warning(String msg) { 1157 if (Level.WARNING.intValue() < levelValue) { 1158 return; 1159 } 1160 log(Level.WARNING, msg); 1161 } 1162 1163 /** 1164 * Log an INFO message. 1165 * <p> 1166 * If the logger is currently enabled for the INFO message 1167 * level then the given message is forwarded to all the 1168 * registered output Handler objects. 1169 * <p> 1170 * @param msg The string message (or a key in the message catalog) 1171 */ 1172 public void info(String msg) { 1173 if (Level.INFO.intValue() < levelValue) { 1174 return; 1175 } 1176 log(Level.INFO, msg); 1177 } 1178 1179 /** 1180 * Log a CONFIG message. 1181 * <p> 1182 * If the logger is currently enabled for the CONFIG message 1183 * level then the given message is forwarded to all the 1184 * registered output Handler objects. 1185 * <p> 1186 * @param msg The string message (or a key in the message catalog) 1187 */ 1188 public void config(String msg) { 1189 if (Level.CONFIG.intValue() < levelValue) { 1190 return; 1191 } 1192 log(Level.CONFIG, msg); 1193 } 1194 1195 /** 1196 * Log a FINE message. 1197 * <p> 1198 * If the logger is currently enabled for the FINE message 1199 * level then the given message is forwarded to all the 1200 * registered output Handler objects. 1201 * <p> 1202 * @param msg The string message (or a key in the message catalog) 1203 */ 1204 public void fine(String msg) { 1205 if (Level.FINE.intValue() < levelValue) { 1206 return; 1207 } 1208 log(Level.FINE, msg); 1209 } 1210 1211 /** 1212 * Log a FINER message. 1213 * <p> 1214 * If the logger is currently enabled for the FINER message 1215 * level then the given message is forwarded to all the 1216 * registered output Handler objects. 1217 * <p> 1218 * @param msg The string message (or a key in the message catalog) 1219 */ 1220 public void finer(String msg) { 1221 if (Level.FINER.intValue() < levelValue) { 1222 return; 1223 } 1224 log(Level.FINER, msg); 1225 } 1226 1227 /** 1228 * Log a FINEST message. 1229 * <p> 1230 * If the logger is currently enabled for the FINEST message 1231 * level then the given message is forwarded to all the 1232 * registered output Handler objects. 1233 * <p> 1234 * @param msg The string message (or a key in the message catalog) 1235 */ 1236 public void finest(String msg) { 1237 if (Level.FINEST.intValue() < levelValue) { 1238 return; 1239 } 1240 log(Level.FINEST, msg); 1241 } 1242 1243 //================================================================ 1244 // End of convenience methods 1245 //================================================================ 1246 1247 /** 1248 * Set the log level specifying which message levels will be 1249 * logged by this logger. Message levels lower than this 1250 * value will be discarded. The level value Level.OFF 1251 * can be used to turn off logging. 1252 * <p> 1253 * If the new level is null, it means that this node should 1254 * inherit its level from its nearest ancestor with a specific 1255 * (non-null) level value. 1256 * 1257 * @param newLevel the new value for the log level (may be null) 1258 * @exception SecurityException if a security manager exists and if 1259 * the caller does not have LoggingPermission("control"). 1260 */ 1261 public void setLevel(Level newLevel) throws SecurityException { 1262 checkPermission(); 1263 synchronized (treeLock) { 1264 levelObject = newLevel; 1265 updateEffectiveLevel(); 1266 } 1267 } 1268 1269 /** 1270 * Get the log Level that has been specified for this Logger. 1271 * The result may be null, which means that this logger's 1272 * effective level will be inherited from its parent. 1273 * 1274 * @return this Logger's level 1275 */ 1276 public Level getLevel() { 1277 return levelObject; 1278 } 1279 1280 /** 1281 * Check if a message of the given level would actually be logged 1282 * by this logger. This check is based on the Loggers effective level, 1283 * which may be inherited from its parent. 1284 * 1285 * @param level a message logging level 1286 * @return true if the given message level is currently being logged. 1287 */ 1288 public boolean isLoggable(Level level) { 1289 if (level.intValue() < levelValue || levelValue == offValue) { 1290 return false; 1291 } 1292 return true; 1293 } 1294 1295 /** 1296 * Get the name for this logger. 1297 * @return logger name. Will be null for anonymous Loggers. 1298 */ 1299 public String getName() { 1300 return name; 1301 } 1302 1303 /** 1304 * Add a log Handler to receive logging messages. 1305 * <p> 1306 * By default, Loggers also send their output to their parent logger. 1307 * Typically the root Logger is configured with a set of Handlers 1308 * that essentially act as default handlers for all loggers. 1309 * 1310 * @param handler a logging Handler 1311 * @exception SecurityException if a security manager exists and if 1312 * the caller does not have LoggingPermission("control"). 1313 */ 1314 public void addHandler(Handler handler) throws SecurityException { 1315 // Check for null handler 1316 handler.getClass(); 1317 checkPermission(); 1318 handlers.add(handler); 1319 } 1320 1321 /** 1322 * Remove a log Handler. 1323 * <P> 1324 * Returns silently if the given Handler is not found or is null 1325 * 1326 * @param handler a logging Handler 1327 * @exception SecurityException if a security manager exists and if 1328 * the caller does not have LoggingPermission("control"). 1329 */ 1330 public void removeHandler(Handler handler) throws SecurityException { 1331 checkPermission(); 1332 if (handler == null) { 1333 return; 1334 } 1335 handlers.remove(handler); 1336 } 1337 1338 /** 1339 * Get the Handlers associated with this logger. 1340 * <p> 1341 * @return an array of all registered Handlers 1342 */ 1343 public Handler[] getHandlers() { 1344 return handlers.toArray(emptyHandlers); 1345 } 1346 1347 /** 1348 * Specify whether or not this logger should send its output 1349 * to its parent Logger. This means that any LogRecords will 1350 * also be written to the parent's Handlers, and potentially 1351 * to its parent, recursively up the namespace. 1352 * 1353 * @param useParentHandlers true if output is to be sent to the 1354 * logger's parent. 1355 * @exception SecurityException if a security manager exists and if 1356 * the caller does not have LoggingPermission("control"). 1357 */ 1358 public void setUseParentHandlers(boolean useParentHandlers) { 1359 checkPermission(); 1360 this.useParentHandlers = useParentHandlers; 1361 } 1362 1363 /** 1364 * Discover whether or not this logger is sending its output 1365 * to its parent logger. 1366 * 1367 * @return true if output is to be sent to the logger's parent 1368 */ 1369 public boolean getUseParentHandlers() { 1370 return useParentHandlers; 1371 } 1372 1373 static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; 1374 1375 private static ResourceBundle findSystemResourceBundle(final Locale locale) { 1376 // the resource bundle is in a restricted package 1377 return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() { 1378 public ResourceBundle run() { 1379 try { 1380 return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, 1381 locale, 1382 ClassLoader.getSystemClassLoader()); 1383 } catch (MissingResourceException e) { 1384 throw new InternalError(e.toString()); 1385 } 1386 } 1387 }); 1388 } 1389 1390 /** 1391 * Private utility method to map a resource bundle name to an 1392 * actual resource bundle, using a simple one-entry cache. 1393 * Returns null for a null name. 1394 * May also return null if we can't find the resource bundle and 1395 * there is no suitable previous cached value. 1396 * 1397 * @param name the ResourceBundle to locate 1398 * @param userCallersClassLoader if true search using the caller's ClassLoader 1399 * @return ResourceBundle specified by name or null if not found 1400 */ 1401 private synchronized ResourceBundle findResourceBundle(String name, 1402 boolean useCallersClassLoader) { 1403 // For all lookups, we first check the thread context class loader 1404 // if it is set. If not, we use the system classloader. If we 1405 // still haven't found it we use the callersClassLoaderRef if it 1406 // is set and useCallersClassLoader is true. We set 1407 // callersClassLoaderRef initially upon creating the logger with a 1408 // non-null resource bundle name. 1409 1410 // Return a null bundle for a null name. 1411 if (name == null) { 1412 return null; 1413 } 1414 1415 Locale currentLocale = Locale.getDefault(); 1416 1417 // Normally we should hit on our simple one entry cache. 1418 if (catalog != null && currentLocale.equals(catalogLocale) 1419 && name.equals(catalogName)) { 1420 return catalog; 1421 } 1422 1423 if (name.equals(SYSTEM_LOGGER_RB_NAME)) { 1424 catalog = findSystemResourceBundle(currentLocale); 1425 catalogName = name; 1426 catalogLocale = currentLocale; 1427 return catalog; 1428 } 1429 1430 // Use the thread's context ClassLoader. If there isn't one, use the 1431 // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}. 1432 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1433 if (cl == null) { 1434 cl = ClassLoader.getSystemClassLoader(); 1435 } 1436 try { 1437 catalog = ResourceBundle.getBundle(name, currentLocale, cl); 1438 catalogName = name; 1439 catalogLocale = currentLocale; 1440 return catalog; 1441 } catch (MissingResourceException ex) { 1442 // We can't find the ResourceBundle in the default 1443 // ClassLoader. Drop through. 1444 } 1445 1446 if (useCallersClassLoader) { 1447 // Try with the caller's ClassLoader 1448 ClassLoader callersClassLoader = getCallersClassLoader(); 1449 if (callersClassLoader != null && callersClassLoader != cl) { 1450 try { 1451 catalog = ResourceBundle.getBundle(name, currentLocale, 1452 callersClassLoader); 1453 catalogName = name; 1454 catalogLocale = currentLocale; 1455 return catalog; 1456 } catch (MissingResourceException ex) { 1457 } 1458 } 1459 } 1460 1461 // If -Djdk.logging.allowStackWalkSearch=true is set, 1462 // does stack walk to search for the resource bundle 1463 if (LoggerHelper.allowStackWalkSearch) { 1464 return findResourceBundleFromStack(name, currentLocale, cl); 1465 } else { 1466 return null; 1467 } 1468 } 1469 1470 /** 1471 * This method will fail when running with a VM that enforces caller-sensitive 1472 * methods and only allows to get the immediate caller. 1473 */ 1474 @CallerSensitive 1475 private synchronized ResourceBundle findResourceBundleFromStack(String name, 1476 Locale locale, 1477 ClassLoader cl) 1478 { 1479 // Android-changed: Use VMStack.getThreadStackTrace. 1480 StackTraceElement[] stack = VMStack.getThreadStackTrace(Thread.currentThread()); 1481 for (int ix = 0; ; ix++) { 1482 Class<?> clz = null; 1483 try { 1484 clz = Class.forName(stack[ix].getClassName()); 1485 } catch (ClassNotFoundException ignored) {} 1486 if (clz == null) { 1487 break; 1488 } 1489 ClassLoader cl2 = clz.getClassLoader(); 1490 if (cl2 == null) { 1491 cl2 = ClassLoader.getSystemClassLoader(); 1492 } 1493 if (cl == cl2) { 1494 // We've already checked this classloader. 1495 continue; 1496 } 1497 cl = cl2; 1498 try { 1499 catalog = ResourceBundle.getBundle(name, locale, cl); 1500 catalogName = name; 1501 catalogLocale = locale; 1502 return catalog; 1503 } catch (MissingResourceException ex) { 1504 } 1505 } 1506 return null; 1507 } 1508 1509 // Private utility method to initialize our one entry 1510 // resource bundle name cache and the callers ClassLoader 1511 // Note: for consistency reasons, we are careful to check 1512 // that a suitable ResourceBundle exists before setting the 1513 // resourceBundleName field. 1514 // Synchronized to prevent races in setting the fields. 1515 private synchronized void setupResourceInfo(String name, 1516 Class<?> callersClass) { 1517 if (name == null) { 1518 return; 1519 } 1520 1521 setCallersClassLoaderRef(callersClass); 1522 if (findResourceBundle(name, true) == null) { 1523 // We've failed to find an expected ResourceBundle. 1524 // unset the caller's ClassLoader since we were unable to find the 1525 // the bundle using it 1526 this.callersClassLoaderRef = null; 1527 throw new MissingResourceException("Can't find " + name + " bundle", 1528 name, ""); 1529 } 1530 resourceBundleName = name; 1531 } 1532 1533 /** 1534 * Return the parent for this Logger. 1535 * <p> 1536 * This method returns the nearest extant parent in the namespace. 1537 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b" 1538 * has been created but no logger "a.b.c" exists, then a call of 1539 * getParent on the Logger "a.b.c.d" will return the Logger "a.b". 1540 * <p> 1541 * The result will be null if it is called on the root Logger 1542 * in the namespace. 1543 * 1544 * @return nearest existing parent Logger 1545 */ 1546 public Logger getParent() { 1547 // Note: this used to be synchronized on treeLock. However, this only 1548 // provided memory semantics, as there was no guarantee that the caller 1549 // would synchronize on treeLock (in fact, there is no way for external 1550 // callers to so synchronize). Therefore, we have made parent volatile 1551 // instead. 1552 return parent; 1553 } 1554 1555 /** 1556 * Set the parent for this Logger. This method is used by 1557 * the LogManager to update a Logger when the namespace changes. 1558 * <p> 1559 * It should not be called from application code. 1560 * <p> 1561 * @param parent the new parent logger 1562 * @exception SecurityException if a security manager exists and if 1563 * the caller does not have LoggingPermission("control"). 1564 */ 1565 public void setParent(Logger parent) { 1566 if (parent == null) { 1567 throw new NullPointerException(); 1568 } 1569 manager.checkPermission(); 1570 doSetParent(parent); 1571 } 1572 1573 // Private method to do the work for parenting a child 1574 // Logger onto a parent logger. 1575 private void doSetParent(Logger newParent) { 1576 1577 // System.err.println("doSetParent \"" + getName() + "\" \"" 1578 // + newParent.getName() + "\""); 1579 1580 synchronized (treeLock) { 1581 1582 // Remove ourself from any previous parent. 1583 LogManager.LoggerWeakRef ref = null; 1584 if (parent != null) { 1585 // assert parent.kids != null; 1586 for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) { 1587 ref = iter.next(); 1588 Logger kid = ref.get(); 1589 if (kid == this) { 1590 // ref is used down below to complete the reparenting 1591 iter.remove(); 1592 break; 1593 } else { 1594 ref = null; 1595 } 1596 } 1597 // We have now removed ourself from our parents' kids. 1598 } 1599 1600 // Set our new parent. 1601 parent = newParent; 1602 if (parent.kids == null) { 1603 parent.kids = new ArrayList<>(2); 1604 } 1605 if (ref == null) { 1606 // we didn't have a previous parent 1607 ref = manager.new LoggerWeakRef(this); 1608 } 1609 ref.setParentRef(new WeakReference<Logger>(parent)); 1610 parent.kids.add(ref); 1611 1612 // As a result of the reparenting, the effective level 1613 // may have changed for us and our children. 1614 updateEffectiveLevel(); 1615 1616 } 1617 } 1618 1619 // Package-level method. 1620 // Remove the weak reference for the specified child Logger from the 1621 // kid list. We should only be called from LoggerWeakRef.dispose(). 1622 final void removeChildLogger(LogManager.LoggerWeakRef child) { 1623 synchronized (treeLock) { 1624 for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) { 1625 LogManager.LoggerWeakRef ref = iter.next(); 1626 if (ref == child) { 1627 iter.remove(); 1628 return; 1629 } 1630 } 1631 } 1632 } 1633 1634 // Recalculate the effective level for this node and 1635 // recursively for our children. 1636 1637 private void updateEffectiveLevel() { 1638 // assert Thread.holdsLock(treeLock); 1639 1640 // Figure out our current effective level. 1641 int newLevelValue; 1642 if (levelObject != null) { 1643 newLevelValue = levelObject.intValue(); 1644 } else { 1645 if (parent != null) { 1646 newLevelValue = parent.levelValue; 1647 } else { 1648 // This may happen during initialization. 1649 newLevelValue = Level.INFO.intValue(); 1650 } 1651 } 1652 1653 // If our effective value hasn't changed, we're done. 1654 if (levelValue == newLevelValue) { 1655 return; 1656 } 1657 1658 levelValue = newLevelValue; 1659 1660 // System.err.println("effective level: \"" + getName() + "\" := " + level); 1661 1662 // Recursively update the level on each of our kids. 1663 if (kids != null) { 1664 for (int i = 0; i < kids.size(); i++) { 1665 LogManager.LoggerWeakRef ref = kids.get(i); 1666 Logger kid = ref.get(); 1667 if (kid != null) { 1668 kid.updateEffectiveLevel(); 1669 } 1670 } 1671 } 1672 } 1673 1674 1675 // Private method to get the potentially inherited 1676 // resource bundle name for this Logger. 1677 // May return null 1678 private String getEffectiveResourceBundleName() { 1679 Logger target = this; 1680 while (target != null) { 1681 String rbn = target.getResourceBundleName(); 1682 if (rbn != null) { 1683 return rbn; 1684 } 1685 target = target.getParent(); 1686 } 1687 return null; 1688 } 1689 1690 1691} 1692