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 27 package java.util.logging; 28 29 import java.lang.ref.WeakReference; 30 import java.security.AccessController; 31 import java.security.PrivilegedAction; 32 import java.util.ArrayList; 33 import java.util.Iterator; 34 import java.util.Locale; 35 import java.util.MissingResourceException; 36 import java.util.ResourceBundle; 37 import java.util.concurrent.CopyOnWriteArrayList; 38 import java.util.function.Supplier; 39 import sun.reflect.CallerSensitive; 40 import sun.reflect.Reflection; 41 42 /** 43 * A Logger object is used to log messages for a specific 44 * system or application component. Loggers are normally named, 45 * using a hierarchical dot-separated namespace. Logger names 46 * can be arbitrary strings, but they should normally be based on 47 * the package name or class name of the logged component, such 48 * as java.net or javax.swing. In addition it is possible to create 49 * "anonymous" Loggers that are not stored in the Logger namespace. 50 * <p> 51 * Logger objects may be obtained by calls on one of the getLogger 52 * factory methods. These will either create a new Logger or 53 * return a suitable existing Logger. It is important to note that 54 * the Logger returned by one of the {@code getLogger} factory methods 55 * may be garbage collected at any time if a strong reference to the 56 * Logger is not kept. 57 * <p> 58 * Logging messages will be forwarded to registered Handler 59 * objects, which can forward the messages to a variety of 60 * destinations, including consoles, files, OS logs, etc. 61 * <p> 62 * Each Logger keeps track of a "parent" Logger, which is its 63 * nearest existing ancestor in the Logger namespace. 64 * <p> 65 * Each Logger has a "Level" associated with it. This reflects 66 * a minimum Level that this logger cares about. If a Logger's 67 * level is set to <tt>null</tt>, then its effective level is inherited 68 * from its parent, which may in turn obtain it recursively from its 69 * parent, and so on up the tree. 70 * <p> 71 * The log level can be configured based on the properties from the 72 * logging configuration file, as described in the description 73 * of the LogManager class. However it may also be dynamically changed 74 * by calls on the Logger.setLevel method. If a logger's level is 75 * changed the change may also affect child loggers, since any child 76 * logger that has <tt>null</tt> as its level will inherit its 77 * effective level from its parent. 78 * <p> 79 * On each logging call the Logger initially performs a cheap 80 * check of the request level (e.g., SEVERE or FINE) against the 81 * effective log level of the logger. If the request level is 82 * lower than the log level, the logging call returns immediately. 83 * <p> 84 * After passing this initial (cheap) test, the Logger will allocate 85 * a LogRecord to describe the logging message. It will then call a 86 * Filter (if present) to do a more detailed check on whether the 87 * record should be published. If that passes it will then publish 88 * the LogRecord to its output Handlers. By default, loggers also 89 * publish to their parent's Handlers, recursively up the tree. 90 * <p> 91 * Each Logger may have a {@code ResourceBundle} associated with it. 92 * The {@code ResourceBundle} may be specified by name, using the 93 * {@link #getLogger(java.lang.String, java.lang.String)} factory 94 * method, or by value - using the {@link 95 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 96 * This bundle will be used for localizing logging messages. 97 * If a Logger does not have its own {@code ResourceBundle} or resource bundle 98 * name, then it will inherit the {@code ResourceBundle} or resource bundle name 99 * from its parent, recursively up the tree. 100 * <p> 101 * Most of the logger output methods take a "msg" argument. This 102 * msg argument may be either a raw value or a localization key. 103 * During formatting, if the logger has (or inherits) a localization 104 * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for 105 * the msg string, then the msg string is replaced by the localized value. 106 * Otherwise the original msg string is used. Typically, formatters use 107 * java.text.MessageFormat style formatting to format parameters, so 108 * for example a format string "{0} {1}" would format two parameters 109 * as strings. 110 * <p> 111 * A set of methods alternatively take a "msgSupplier" instead of a "msg" 112 * argument. These methods take a {@link Supplier}{@code <String>} function 113 * which is invoked to construct the desired log message only when the message 114 * actually is to be logged based on the effective log level thus eliminating 115 * unnecessary message construction. For example, if the developer wants to 116 * log system health status for diagnosis, with the String-accepting version, 117 * the code would look like: 118 <pre><code> 119 120 class DiagnosisMessages { 121 static String systemHealthStatus() { 122 // collect system health information 123 ... 124 } 125 } 126 ... 127 logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus()); 128 </code></pre> 129 * With the above code, the health status is collected unnecessarily even when 130 * the log level FINER is disabled. With the Supplier-accepting version as 131 * below, the status will only be collected when the log level FINER is 132 * enabled. 133 <pre><code> 134 135 logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus); 136 </code></pre> 137 * <p> 138 * When looking for a {@code ResourceBundle}, the logger will first look at 139 * whether a bundle was specified using {@link 140 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then 141 * only whether a resource bundle name was specified through the {@link 142 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 143 * If no {@code ResourceBundle} or no resource bundle name is found, 144 * then it will use the nearest {@code ResourceBundle} or resource bundle 145 * name inherited from its parent tree.<br> 146 * When a {@code ResourceBundle} was inherited or specified through the 147 * {@link 148 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then 149 * that {@code ResourceBundle} will be used. Otherwise if the logger only 150 * has or inherited a resource bundle name, then that resource bundle name 151 * will be mapped to a {@code ResourceBundle} object, using the default Locale 152 * at the time of logging. 153 * <br id="ResourceBundleMapping">When mapping resource bundle names to 154 * {@code ResourceBundle} objects, the logger will first try to use the 155 * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class 156 * loader} to map the given resource bundle name to a {@code ResourceBundle}. 157 * If the thread context class loader is {@code null}, it will try the 158 * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader} 159 * instead. If the {@code ResourceBundle} is still not found, it will use the 160 * class loader of the first caller of the {@link 161 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 162 * <p> 163 * Formatting (including localization) is the responsibility of 164 * the output Handler, which will typically call a Formatter. 165 * <p> 166 * Note that formatting need not occur synchronously. It may be delayed 167 * until a LogRecord is actually written to an external sink. 168 * <p> 169 * The logging methods are grouped in five main categories: 170 * <ul> 171 * <li><p> 172 * There are a set of "log" methods that take a log level, a message 173 * string, and optionally some parameters to the message string. 174 * <li><p> 175 * There are a set of "logp" methods (for "log precise") that are 176 * like the "log" methods, but also take an explicit source class name 177 * and method name. 178 * <li><p> 179 * There are a set of "logrb" method (for "log with resource bundle") 180 * that are like the "logp" method, but also take an explicit resource 181 * bundle object for use in localizing the log message. 182 * <li><p> 183 * There are convenience methods for tracing method entries (the 184 * "entering" methods), method returns (the "exiting" methods) and 185 * throwing exceptions (the "throwing" methods). 186 * <li><p> 187 * Finally, there are a set of convenience methods for use in the 188 * very simplest cases, when a developer simply wants to log a 189 * simple string at a given log level. These methods are named 190 * after the standard Level names ("severe", "warning", "info", etc.) 191 * and take a single argument, a message string. 192 * </ul> 193 * <p> 194 * For the methods that do not take an explicit source name and 195 * method name, the Logging framework will make a "best effort" 196 * to determine which class and method called into the logging method. 197 * However, it is important to realize that this automatically inferred 198 * information may only be approximate (or may even be quite wrong!). 199 * Virtual machines are allowed to do extensive optimizations when 200 * JITing and may entirely remove stack frames, making it impossible 201 * to reliably locate the calling class and method. 202 * <P> 203 * All methods on Logger are multi-thread safe. 204 * <p> 205 * <b>Subclassing Information:</b> Note that a LogManager class may 206 * provide its own implementation of named Loggers for any point in 207 * the namespace. Therefore, any subclasses of Logger (unless they 208 * are implemented in conjunction with a new LogManager class) should 209 * take care to obtain a Logger instance from the LogManager class and 210 * should delegate operations such as "isLoggable" and "log(LogRecord)" 211 * to that instance. Note that in order to intercept all logging 212 * output, subclasses need only override the log(LogRecord) method. 213 * All the other logging methods are implemented as calls on this 214 * log(LogRecord) method. 215 * 216 * @since 1.4 217 */ 218 public class Logger { 219 private static final Handler emptyHandlers[] = new Handler[0]; 220 private static final int offValue = Level.OFF.intValue(); 221 private LogManager manager; 222 private String name; 223 private final CopyOnWriteArrayList<Handler> handlers = 224 new CopyOnWriteArrayList<>(); 225 private String resourceBundleName; // Base name of the bundle. 226 private ResourceBundle userBundle; // Bundle set through setResourceBundle. 227 private volatile boolean useParentHandlers = true; 228 private volatile Filter filter; 229 private boolean anonymous; 230 231 // Cache to speed up behavior of findResourceBundle: 232 private ResourceBundle catalog; // Cached resource bundle 233 private String catalogName; // name associated with catalog 234 private Locale catalogLocale; // locale associated with catalog 235 236 // The fields relating to parent-child relationships and levels 237 // are managed under a separate lock, the treeLock. 238 private static final Object treeLock = new Object(); 239 // We keep weak references from parents to children, but strong 240 // references from children to parents. 241 private volatile Logger parent; // our nearest parent. 242 private ArrayList<LogManager.LoggerWeakRef> kids; // WeakReferences to loggers that have us as parent 243 private volatile Level levelObject; 244 private volatile int levelValue; // current effective level value 245 private WeakReference<ClassLoader> callersClassLoaderRef; 246 247 /** 248 * GLOBAL_LOGGER_NAME is a name for the global logger. 249 * 250 * @since 1.6 251 */ 252 public static final String GLOBAL_LOGGER_NAME = "global"; 253 254 /** 255 * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME. 256 * 257 * @return global logger object 258 * @since 1.7 259 */ 260 public static final Logger getGlobal() { 261 // In order to break a cyclic dependence between the LogManager 262 // and Logger static initializers causing deadlocks, the global 263 // logger is created with a special constructor that does not 264 // initialize its log manager. 265 // 266 // If an application calls Logger.getGlobal() before any logger 267 // has been initialized, it is therefore possible that the 268 // LogManager class has not been initialized yet, and therefore 269 // Logger.global.manager will be null. 270 // 271 // In order to finish the initialization of the global logger, we 272 // will therefore call LogManager.getLogManager() here. 273 // 274 // To prevent race conditions we also need to call 275 // LogManager.getLogManager() unconditionally here. 276 // Indeed we cannot rely on the observed value of global.manager, 277 // because global.manager will become not null somewhere during 278 // the initialization of LogManager. 279 // If two threads are calling getGlobal() concurrently, one thread 280 // will see global.manager null and call LogManager.getLogManager(), 281 // but the other thread could come in at a time when global.manager 282 // is already set although ensureLogManagerInitialized is not finished 283 // yet... 284 // Calling LogManager.getLogManager() unconditionally will fix that. 285 286 LogManager.getLogManager(); 287 288 // Now the global LogManager should be initialized, 289 // and the global logger should have been added to 290 // it, unless we were called within the constructor of a LogManager 291 // subclass installed as LogManager, in which case global.manager 292 // would still be null, and global will be lazily initialized later on. 293 294 return global; 295 } 296 297 /** 298 * The "global" Logger object is provided as a convenience to developers 299 * who are making casual use of the Logging package. Developers 300 * who are making serious use of the logging package (for example 301 * in products) should create and use their own Logger objects, 302 * with appropriate names, so that logging can be controlled on a 303 * suitable per-Logger granularity. Developers also need to keep a 304 * strong reference to their Logger objects to prevent them from 305 * being garbage collected. 306 * <p> 307 * @deprecated Initialization of this field is prone to deadlocks. 308 * The field must be initialized by the Logger class initialization 309 * which may cause deadlocks with the LogManager class initialization. 310 * In such cases two class initialization wait for each other to complete. 311 * The preferred way to get the global logger object is via the call 312 * <code>Logger.getGlobal()</code>. 313 * For compatibility with old JDK versions where the 314 * <code>Logger.getGlobal()</code> is not available use the call 315 * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code> 316 * or <code>Logger.getLogger("global")</code>. 317 */ 318 @Deprecated 319 public static final Logger global = new Logger(GLOBAL_LOGGER_NAME); 320 321 /** 322 * Protected method to construct a logger for a named subsystem. 323 * <p> 324 * The logger will be initially configured with a null Level 325 * and with useParentHandlers set to true. 326 * 327 * @param name A name for the logger. This should 328 * be a dot-separated name and should normally 329 * be based on the package name or class name 330 * of the subsystem, such as java.net 331 * or javax.swing. It may be null for anonymous Loggers. 332 * @param resourceBundleName name of ResourceBundle to be used for localizing 333 * messages for this logger. May be null if none 334 * of the messages require localization. 335 * @throws MissingResourceException if the resourceBundleName is non-null and 336 * no corresponding resource can be found. 337 */ 338 protected Logger(String name, String resourceBundleName) { 339 this(name, resourceBundleName, null, LogManager.getLogManager()); 340 } 341 342 Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) { 343 this.manager = manager; 344 setupResourceInfo(resourceBundleName, caller); 345 this.name = name; 346 levelValue = Level.INFO.intValue(); 347 } 348 349 private void setCallersClassLoaderRef(Class<?> caller) { 350 ClassLoader callersClassLoader = ((caller != null) 351 ? caller.getClassLoader() 352 : null); 353 if (callersClassLoader != null) { 354 this.callersClassLoaderRef = new WeakReference<>(callersClassLoader); 355 } 356 } 357 358 private ClassLoader getCallersClassLoader() { 359 return (callersClassLoaderRef != null) 360 ? callersClassLoaderRef.get() 361 : null; 362 } 363 364 // This constructor is used only to create the global Logger. 365 // It is needed to break a cyclic dependence between the LogManager 366 // and Logger static initializers causing deadlocks. 367 private Logger(String name) { 368 // The manager field is not initialized here. 369 this.name = name; 370 levelValue = Level.INFO.intValue(); 371 } 372 373 // It is called from LoggerContext.addLocalLogger() when the logger 374 // is actually added to a LogManager. 375 void setLogManager(LogManager manager) { 376 this.manager = manager; 377 } 378 379 private void checkPermission() throws SecurityException { 380 if (!anonymous) { 381 if (manager == null) { 382 // Complete initialization of the global Logger. 383 manager = LogManager.getLogManager(); 384 } 385 manager.checkPermission(); 386 } 387 } 388 389 // Until all JDK code converted to call sun.util.logging.PlatformLogger 390 // (see 7054233), we need to determine if Logger.getLogger is to add 391 // a system logger or user logger. 392 // 393 // As an interim solution, if the immediate caller whose caller loader is 394 // null, we assume it's a system logger and add it to the system context. 395 // These system loggers only set the resource bundle to the given 396 // resource bundle name (rather than the default system resource bundle). 397 private static class SystemLoggerHelper { 398 static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); 399 private static boolean getBooleanProperty(final String key) { 400 String s = AccessController.doPrivileged(new PrivilegedAction<String>() { 401 @Override 402 public String run() { 403 return System.getProperty(key); 404 } 405 }); 406 return Boolean.valueOf(s); 407 } 408 } 409 410 private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 411 LogManager manager = LogManager.getLogManager(); 412 SecurityManager sm = System.getSecurityManager(); 413 if (sm != null && !SystemLoggerHelper.disableCallerCheck) { 414 if (caller.getClassLoader() == null) { 415 return manager.demandSystemLogger(name, resourceBundleName); 416 } 417 } 418 return manager.demandLogger(name, resourceBundleName, caller); 419 // ends up calling new Logger(name, resourceBundleName, caller) 420 // iff the logger doesn't exist already 421 } 422 423 /** 424 * Find or create a logger for a named subsystem. If a logger has 425 * already been created with the given name it is returned. Otherwise 426 * a new logger is created. 427 * <p> 428 * If a new logger is created its log level will be configured 429 * based on the LogManager configuration and it will configured 430 * to also send logging output to its parent's Handlers. It will 431 * be registered in the LogManager global namespace. 432 * <p> 433 * Note: The LogManager may only retain a weak reference to the newly 434 * created Logger. It is important to understand that a previously 435 * created Logger with the given name may be garbage collected at any 436 * time if there is no strong reference to the Logger. In particular, 437 * this means that two back-to-back calls like 438 * {@code getLogger("MyLogger").log(...)} may use different Logger 439 * objects named "MyLogger" if there is no strong reference to the 440 * Logger named "MyLogger" elsewhere in the program. 441 * 442 * @param name A name for the logger. This should 443 * be a dot-separated name and should normally 444 * be based on the package name or class name 445 * of the subsystem, such as java.net 446 * or javax.swing 447 * @return a suitable Logger 448 * @throws NullPointerException if the name is null. 449 */ 450 451 // Synchronization is not required here. All synchronization for 452 // adding a new Logger object is handled by LogManager.addLogger(). 453 @CallerSensitive 454 public static Logger getLogger(String name) { 455 // This method is intentionally not a wrapper around a call 456 // to getLogger(name, resourceBundleName). If it were then 457 // this sequence: 458 // 459 // getLogger("Foo", "resourceBundleForFoo"); 460 // getLogger("Foo"); 461 // 462 // would throw an IllegalArgumentException in the second call 463 // because the wrapper would result in an attempt to replace 464 // the existing "resourceBundleForFoo" with null. 465 return demandLogger(name, null, Reflection.getCallerClass()); 466 } 467 468 /** 469 * Find or create a logger for a named subsystem. If a logger has 470 * already been created with the given name it is returned. Otherwise 471 * a new logger is created. 472 * <p> 473 * If a new logger is created its log level will be configured 474 * based on the LogManager and it will configured to also send logging 475 * output to its parent's Handlers. It will be registered in 476 * the LogManager global namespace. 477 * <p> 478 * Note: The LogManager may only retain a weak reference to the newly 479 * created Logger. It is important to understand that a previously 480 * created Logger with the given name may be garbage collected at any 481 * time if there is no strong reference to the Logger. In particular, 482 * this means that two back-to-back calls like 483 * {@code getLogger("MyLogger", ...).log(...)} may use different Logger 484 * objects named "MyLogger" if there is no strong reference to the 485 * Logger named "MyLogger" elsewhere in the program. 486 * <p> 487 * If the named Logger already exists and does not yet have a 488 * localization resource bundle then the given resource bundle 489 * name is used. If the named Logger already exists and has 490 * a different resource bundle name then an IllegalArgumentException 491 * is thrown. 492 * <p> 493 * @param name A name for the logger. This should 494 * be a dot-separated name and should normally 495 * be based on the package name or class name 496 * of the subsystem, such as java.net 497 * or javax.swing 498 * @param resourceBundleName name of ResourceBundle to be used for localizing 499 * messages for this logger. May be {@code null} 500 * if none of the messages require localization. 501 * @return a suitable Logger 502 * @throws MissingResourceException if the resourceBundleName is non-null and 503 * no corresponding resource can be found. 504 * @throws IllegalArgumentException if the Logger already exists and uses 505 * a different resource bundle name; or if 506 * {@code resourceBundleName} is {@code null} but the named 507 * logger has a resource bundle set. 508 * @throws NullPointerException if the name is null. 509 */ 510 511 // Synchronization is not required here. All synchronization for 512 // adding a new Logger object is handled by LogManager.addLogger(). 513 @CallerSensitive 514 public static Logger getLogger(String name, String resourceBundleName) { 515 Class<?> callerClass = Reflection.getCallerClass(); 516 Logger result = demandLogger(name, resourceBundleName, callerClass); 517 518 // MissingResourceException or IllegalArgumentException can be 519 // thrown by setupResourceInfo(). 520 // We have to set the callers ClassLoader here in case demandLogger 521 // above found a previously created Logger. This can happen, for 522 // example, if Logger.getLogger(name) is called and subsequently 523 // Logger.getLogger(name, resourceBundleName) is called. In this case 524 // we won't necessarily have the correct classloader saved away, so 525 // we need to set it here, too. 526 527 result.setupResourceInfo(resourceBundleName, callerClass); 528 return result; 529 } 530 531 // package-private 532 // Add a platform logger to the system context. 533 // i.e. caller of sun.util.logging.PlatformLogger.getLogger 534 static Logger getPlatformLogger(String name) { 535 LogManager manager = LogManager.getLogManager(); 536 537 // all loggers in the system context will default to 538 // the system logger's resource bundle 539 Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME); 540 return result; 541 } 542 543 /** 544 * Create an anonymous Logger. The newly created Logger is not 545 * registered in the LogManager namespace. There will be no 546 * access checks on updates to the logger. 547 * <p> 548 * This factory method is primarily intended for use from applets. 549 * Because the resulting Logger is anonymous it can be kept private 550 * by the creating class. This removes the need for normal security 551 * checks, which in turn allows untrusted applet code to update 552 * the control state of the Logger. For example an applet can do 553 * a setLevel or an addHandler on an anonymous Logger. 554 * <p> 555 * Even although the new logger is anonymous, it is configured 556 * to have the root logger ("") as its parent. This means that 557 * by default it inherits its effective level and handlers 558 * from the root logger. Changing its parent via the 559 * {@link #setParent(java.util.logging.Logger) setParent} method 560 * will still require the security permission specified by that method. 561 * <p> 562 * 563 * @return a newly created private Logger 564 */ 565 public static Logger getAnonymousLogger() { 566 return getAnonymousLogger(null); 567 } 568 569 /** 570 * Create an anonymous Logger. The newly created Logger is not 571 * registered in the LogManager namespace. There will be no 572 * access checks on updates to the logger. 573 * <p> 574 * This factory method is primarily intended for use from applets. 575 * Because the resulting Logger is anonymous it can be kept private 576 * by the creating class. This removes the need for normal security 577 * checks, which in turn allows untrusted applet code to update 578 * the control state of the Logger. For example an applet can do 579 * a setLevel or an addHandler on an anonymous Logger. 580 * <p> 581 * Even although the new logger is anonymous, it is configured 582 * to have the root logger ("") as its parent. This means that 583 * by default it inherits its effective level and handlers 584 * from the root logger. Changing its parent via the 585 * {@link #setParent(java.util.logging.Logger) setParent} method 586 * will still require the security permission specified by that method. 587 * <p> 588 * @param resourceBundleName name of ResourceBundle to be used for localizing 589 * messages for this logger. 590 * May be null if none of the messages require localization. 591 * @return a newly created private Logger 592 * @throws MissingResourceException if the resourceBundleName is non-null and 593 * no corresponding resource can be found. 594 */ 595 596 // Synchronization is not required here. All synchronization for 597 // adding a new anonymous Logger object is handled by doSetParent(). 598 @CallerSensitive 599 public static Logger getAnonymousLogger(String resourceBundleName) { 600 LogManager manager = LogManager.getLogManager(); 601 // cleanup some Loggers that have been GC'ed 602 manager.drainLoggerRefQueueBounded(); 603 Logger result = new Logger(null, resourceBundleName, 604 Reflection.getCallerClass(), manager); 605 result.anonymous = true; 606 Logger root = manager.getLogger(""); 607 result.doSetParent(root); 608 return result; 609 } 610 611 /** 612 * Retrieve the localization resource bundle for this 613 * logger. 614 * This method will return a {@code ResourceBundle} that was either 615 * set by the {@link 616 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or 617 * <a href="#ResourceBundleMapping">mapped from the 618 * the resource bundle name</a> set via the {@link 619 * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory 620 * method for the current default locale. 621 * <br>Note that if the result is {@code null}, then the Logger will use a resource 622 * bundle or resource bundle name inherited from its parent. 623 * 624 * @return localization bundle (may be {@code null}) 625 */ 626 public ResourceBundle getResourceBundle() { 627 return findResourceBundle(getResourceBundleName(), true); 628 } 629 630 /** 631 * Retrieve the localization resource bundle name for this 632 * logger. 633 * This is either the name specified through the {@link 634 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method, 635 * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the 636 * ResourceBundle set through {@link 637 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 638 * <br>Note that if the result is {@code null}, then the Logger will use a resource 639 * bundle or resource bundle name inherited from its parent. 640 * 641 * @return localization bundle name (may be {@code null}) 642 */ 643 public String getResourceBundleName() { 644 return resourceBundleName; 645 } 646 647 /** 648 * Set a filter to control output on this Logger. 649 * <P> 650 * After passing the initial "level" check, the Logger will 651 * call this Filter to check if a log record should really 652 * be published. 653 * 654 * @param newFilter a filter object (may be null) 655 * @throws SecurityException if a security manager exists, 656 * this logger is not anonymous, and the caller 657 * does not have LoggingPermission("control"). 658 */ 659 public void setFilter(Filter newFilter) throws SecurityException { 660 checkPermission(); 661 filter = newFilter; 662 } 663 664 /** 665 * Get the current filter for this Logger. 666 * 667 * @return a filter object (may be null) 668 */ 669 public Filter getFilter() { 670 return filter; 671 } 672 673 /** 674 * Log a LogRecord. 675 * <p> 676 * All the other logging methods in this class call through 677 * this method to actually perform any logging. Subclasses can 678 * override this single method to capture all log activity. 679 * 680 * @param record the LogRecord to be published 681 */ 682 public void log(LogRecord record) { 683 if (!isLoggable(record.getLevel())) { 684 return; 685 } 686 Filter theFilter = filter; 687 if (theFilter != null && !theFilter.isLoggable(record)) { 688 return; 689 } 690 691 // Post the LogRecord to all our Handlers, and then to 692 // our parents' handlers, all the way up the tree. 693 694 Logger logger = this; 695 while (logger != null) { 696 for (Handler handler : logger.getHandlers()) { 697 handler.publish(record); 698 } 699 700 if (!logger.getUseParentHandlers()) { 701 break; 702 } 703 704 logger = logger.getParent(); 705 } 706 } 707 708 // private support method for logging. 709 // We fill in the logger name, resource bundle name, and 710 // resource bundle and then call "void log(LogRecord)". 711 private void doLog(LogRecord lr) { 712 lr.setLoggerName(name); 713 final ResourceBundle bundle = getEffectiveResourceBundle(); 714 final String ebname = getEffectiveResourceBundleName(); 715 if (ebname != null && bundle != null) { 716 lr.setResourceBundleName(ebname); 717 lr.setResourceBundle(bundle); 718 } 719 log(lr); 720 } 721 722 723 //================================================================ 724 // Start of convenience methods WITHOUT className and methodName 725 //================================================================ 726 727 /** 728 * Log a message, with no arguments. 729 * <p> 730 * If the logger is currently enabled for the given message 731 * level then the given message is forwarded to all the 732 * registered output Handler objects. 733 * <p> 734 * @param level One of the message level identifiers, e.g., SEVERE 735 * @param msg The string message (or a key in the message catalog) 736 */ 737 public void log(Level level, String msg) { 738 if (!isLoggable(level)) { 739 return; 740 } 741 LogRecord lr = new LogRecord(level, msg); 742 doLog(lr); 743 } 744 745 /** 746 * Log a message, which is only to be constructed if the logging level 747 * is such that the message will actually be logged. 748 * <p> 749 * If the logger is currently enabled for the given message 750 * level then the message is constructed by invoking the provided 751 * supplier function and forwarded to all the registered output 752 * Handler objects. 753 * <p> 754 * @param level One of the message level identifiers, e.g., SEVERE 755 * @param msgSupplier A function, which when called, produces the 756 * desired log message 757 */ 758 public void log(Level level, Supplier<String> msgSupplier) { 759 if (!isLoggable(level)) { 760 return; 761 } 762 LogRecord lr = new LogRecord(level, msgSupplier.get()); 763 doLog(lr); 764 } 765 766 /** 767 * Log a message, with one object parameter. 768 * <p> 769 * If the logger is currently enabled for the given message 770 * level then a corresponding LogRecord is created and forwarded 771 * to all the registered output Handler objects. 772 * <p> 773 * @param level One of the message level identifiers, e.g., SEVERE 774 * @param msg The string message (or a key in the message catalog) 775 * @param param1 parameter to the message 776 */ 777 public void log(Level level, String msg, Object param1) { 778 if (!isLoggable(level)) { 779 return; 780 } 781 LogRecord lr = new LogRecord(level, msg); 782 Object params[] = { param1 }; 783 lr.setParameters(params); 784 doLog(lr); 785 } 786 787 /** 788 * Log a message, with an array of object arguments. 789 * <p> 790 * If the logger is currently enabled for the given message 791 * level then a corresponding LogRecord is created and forwarded 792 * to all the registered output Handler objects. 793 * <p> 794 * @param level One of the message level identifiers, e.g., SEVERE 795 * @param msg The string message (or a key in the message catalog) 796 * @param params array of parameters to the message 797 */ 798 public void log(Level level, String msg, Object params[]) { 799 if (!isLoggable(level)) { 800 return; 801 } 802 LogRecord lr = new LogRecord(level, msg); 803 lr.setParameters(params); 804 doLog(lr); 805 } 806 807 /** 808 * Log a message, with associated Throwable information. 809 * <p> 810 * If the logger is currently enabled for the given message 811 * level then the given arguments are stored in a LogRecord 812 * which is forwarded to all registered output handlers. 813 * <p> 814 * Note that the thrown argument is stored in the LogRecord thrown 815 * property, rather than the LogRecord parameters property. Thus it is 816 * processed specially by output Formatters and is not treated 817 * as a formatting parameter to the LogRecord message property. 818 * <p> 819 * @param level One of the message level identifiers, e.g., SEVERE 820 * @param msg The string message (or a key in the message catalog) 821 * @param thrown Throwable associated with log message. 822 */ 823 public void log(Level level, String msg, Throwable thrown) { 824 if (!isLoggable(level)) { 825 return; 826 } 827 LogRecord lr = new LogRecord(level, msg); 828 lr.setThrown(thrown); 829 doLog(lr); 830 } 831 832 /** 833 * Log a lazily constructed message, with associated Throwable information. 834 * <p> 835 * If the logger is currently enabled for the given message level then the 836 * message is constructed by invoking the provided supplier function. The 837 * message and the given {@link Throwable} are then stored in a {@link 838 * LogRecord} which is forwarded to all registered output handlers. 839 * <p> 840 * Note that the thrown argument is stored in the LogRecord thrown 841 * property, rather than the LogRecord parameters property. Thus it is 842 * processed specially by output Formatters and is not treated 843 * as a formatting parameter to the LogRecord message property. 844 * <p> 845 * @param level One of the message level identifiers, e.g., SEVERE 846 * @param thrown Throwable associated with log message. 847 * @param msgSupplier A function, which when called, produces the 848 * desired log message 849 * @since 1.8 850 */ 851 public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) { 852 if (!isLoggable(level)) { 853 return; 854 } 855 LogRecord lr = new LogRecord(level, msgSupplier.get()); 856 lr.setThrown(thrown); 857 doLog(lr); 858 } 859 860 //================================================================ 861 // Start of convenience methods WITH className and methodName 862 //================================================================ 863 864 /** 865 * Log a message, specifying source class and method, 866 * with no arguments. 867 * <p> 868 * If the logger is currently enabled for the given message 869 * level then the given message is forwarded to all the 870 * registered output Handler objects. 871 * <p> 872 * @param level One of the message level identifiers, e.g., SEVERE 873 * @param sourceClass name of class that issued the logging request 874 * @param sourceMethod name of method that issued the logging request 875 * @param msg The string message (or a key in the message catalog) 876 */ 877 public void logp(Level level, String sourceClass, String sourceMethod, String msg) { 878 if (!isLoggable(level)) { 879 return; 880 } 881 LogRecord lr = new LogRecord(level, msg); 882 lr.setSourceClassName(sourceClass); 883 lr.setSourceMethodName(sourceMethod); 884 doLog(lr); 885 } 886 887 /** 888 * Log a lazily constructed message, specifying source class and method, 889 * with no arguments. 890 * <p> 891 * If the logger is currently enabled for the given message 892 * level then the message is constructed by invoking the provided 893 * supplier function and forwarded to all the registered output 894 * Handler objects. 895 * <p> 896 * @param level One of the message level identifiers, e.g., SEVERE 897 * @param sourceClass name of class that issued the logging request 898 * @param sourceMethod name of method that issued the logging request 899 * @param msgSupplier A function, which when called, produces the 900 * desired log message 901 * @since 1.8 902 */ 903 public void logp(Level level, String sourceClass, String sourceMethod, 904 Supplier<String> msgSupplier) { 905 if (!isLoggable(level)) { 906 return; 907 } 908 LogRecord lr = new LogRecord(level, msgSupplier.get()); 909 lr.setSourceClassName(sourceClass); 910 lr.setSourceMethodName(sourceMethod); 911 doLog(lr); 912 } 913 914 /** 915 * Log a message, specifying source class and method, 916 * with a single object parameter to the log message. 917 * <p> 918 * If the logger is currently enabled for the given message 919 * level then a corresponding LogRecord is created and forwarded 920 * to all the registered output Handler objects. 921 * <p> 922 * @param level One of the message level identifiers, e.g., SEVERE 923 * @param sourceClass name of class that issued the logging request 924 * @param sourceMethod name of method that issued the logging request 925 * @param msg The string message (or a key in the message catalog) 926 * @param param1 Parameter to the log message. 927 */ 928 public void logp(Level level, String sourceClass, String sourceMethod, 929 String msg, Object param1) { 930 if (!isLoggable(level)) { 931 return; 932 } 933 LogRecord lr = new LogRecord(level, msg); 934 lr.setSourceClassName(sourceClass); 935 lr.setSourceMethodName(sourceMethod); 936 Object params[] = { param1 }; 937 lr.setParameters(params); 938 doLog(lr); 939 } 940 941 /** 942 * Log a message, specifying source class and method, 943 * with an array of object arguments. 944 * <p> 945 * If the logger is currently enabled for the given message 946 * level then a corresponding LogRecord is created and forwarded 947 * to all the registered output Handler objects. 948 * <p> 949 * @param level One of the message level identifiers, e.g., SEVERE 950 * @param sourceClass name of class that issued the logging request 951 * @param sourceMethod name of method that issued the logging request 952 * @param msg The string message (or a key in the message catalog) 953 * @param params Array of parameters to the message 954 */ 955 public void logp(Level level, String sourceClass, String sourceMethod, 956 String msg, Object params[]) { 957 if (!isLoggable(level)) { 958 return; 959 } 960 LogRecord lr = new LogRecord(level, msg); 961 lr.setSourceClassName(sourceClass); 962 lr.setSourceMethodName(sourceMethod); 963 lr.setParameters(params); 964 doLog(lr); 965 } 966 967 /** 968 * Log a message, specifying source class and method, 969 * with associated Throwable information. 970 * <p> 971 * If the logger is currently enabled for the given message 972 * level then the given arguments are stored in a LogRecord 973 * which is forwarded to all registered output handlers. 974 * <p> 975 * Note that the thrown argument is stored in the LogRecord thrown 976 * property, rather than the LogRecord parameters property. Thus it is 977 * processed specially by output Formatters and is not treated 978 * as a formatting parameter to the LogRecord message property. 979 * <p> 980 * @param level One of the message level identifiers, e.g., SEVERE 981 * @param sourceClass name of class that issued the logging request 982 * @param sourceMethod name of method that issued the logging request 983 * @param msg The string message (or a key in the message catalog) 984 * @param thrown Throwable associated with log message. 985 */ 986 public void logp(Level level, String sourceClass, String sourceMethod, 987 String msg, Throwable thrown) { 988 if (!isLoggable(level)) { 989 return; 990 } 991 LogRecord lr = new LogRecord(level, msg); 992 lr.setSourceClassName(sourceClass); 993 lr.setSourceMethodName(sourceMethod); 994 lr.setThrown(thrown); 995 doLog(lr); 996 } 997 998 /** 999 * Log a lazily constructed message, specifying source class and method, 1000 * with associated Throwable information. 1001 * <p> 1002 * If the logger is currently enabled for the given message level then the 1003 * message is constructed by invoking the provided supplier function. The 1004 * message and the given {@link Throwable} are then stored in a {@link 1005 * LogRecord} which is forwarded to all registered output handlers. 1006 * <p> 1007 * Note that the thrown argument is stored in the LogRecord thrown 1008 * property, rather than the LogRecord parameters property. Thus it is 1009 * processed specially by output Formatters and is not treated 1010 * as a formatting parameter to the LogRecord message property. 1011 * <p> 1012 * @param level One of the message level identifiers, e.g., SEVERE 1013 * @param sourceClass name of class that issued the logging request 1014 * @param sourceMethod name of method that issued the logging request 1015 * @param thrown Throwable associated with log message. 1016 * @param msgSupplier A function, which when called, produces the 1017 * desired log message 1018 * @since 1.8 1019 */ 1020 public void logp(Level level, String sourceClass, String sourceMethod, 1021 Throwable thrown, Supplier<String> msgSupplier) { 1022 if (!isLoggable(level)) { 1023 return; 1024 } 1025 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1026 lr.setSourceClassName(sourceClass); 1027 lr.setSourceMethodName(sourceMethod); 1028 lr.setThrown(thrown); 1029 doLog(lr); 1030 } 1031 1032 1033 //========================================================================= 1034 // Start of convenience methods WITH className, methodName and bundle name. 1035 //========================================================================= 1036 1037 // Private support method for logging for "logrb" methods. 1038 // We fill in the logger name, resource bundle name, and 1039 // resource bundle and then call "void log(LogRecord)". 1040 private void doLog(LogRecord lr, String rbname) { 1041 lr.setLoggerName(name); 1042 if (rbname != null) { 1043 lr.setResourceBundleName(rbname); 1044 lr.setResourceBundle(findResourceBundle(rbname, false)); 1045 } 1046 log(lr); 1047 } 1048 1049 // Private support method for logging for "logrb" methods. 1050 private void doLog(LogRecord lr, ResourceBundle rb) { 1051 lr.setLoggerName(name); 1052 if (rb != null) { 1053 lr.setResourceBundleName(rb.getBaseBundleName()); 1054 lr.setResourceBundle(rb); 1055 } 1056 log(lr); 1057 } 1058 1059 /** 1060 * Log a message, specifying source class, method, and resource bundle name 1061 * with no arguments. 1062 * <p> 1063 * If the logger is currently enabled for the given message 1064 * level then the given message is forwarded to all the 1065 * registered output Handler objects. 1066 * <p> 1067 * The msg string is localized using the named resource bundle. If the 1068 * resource bundle name is null, or an empty String or invalid 1069 * then the msg string is not localized. 1070 * <p> 1071 * @param level One of the message level identifiers, e.g., SEVERE 1072 * @param sourceClass name of class that issued the logging request 1073 * @param sourceMethod name of method that issued the logging request 1074 * @param bundleName name of resource bundle to localize msg, 1075 * can be null 1076 * @param msg The string message (or a key in the message catalog) 1077 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1078 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1079 * java.lang.Object...)} instead. 1080 */ 1081 @Deprecated 1082 public void logrb(Level level, String sourceClass, String sourceMethod, 1083 String bundleName, String msg) { 1084 if (!isLoggable(level)) { 1085 return; 1086 } 1087 LogRecord lr = new LogRecord(level, msg); 1088 lr.setSourceClassName(sourceClass); 1089 lr.setSourceMethodName(sourceMethod); 1090 doLog(lr, bundleName); 1091 } 1092 1093 /** 1094 * Log a message, specifying source class, method, and resource bundle name, 1095 * with a single object parameter to the log message. 1096 * <p> 1097 * If the logger is currently enabled for the given message 1098 * level then a corresponding LogRecord is created and forwarded 1099 * to all the registered output Handler objects. 1100 * <p> 1101 * The msg string is localized using the named resource bundle. If the 1102 * resource bundle name is null, or an empty String or invalid 1103 * then the msg string is not localized. 1104 * <p> 1105 * @param level One of the message level identifiers, e.g., SEVERE 1106 * @param sourceClass name of class that issued the logging request 1107 * @param sourceMethod name of method that issued the logging request 1108 * @param bundleName name of resource bundle to localize msg, 1109 * can be null 1110 * @param msg The string message (or a key in the message catalog) 1111 * @param param1 Parameter to the log message. 1112 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1113 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1114 * java.lang.Object...)} instead 1115 */ 1116 @Deprecated 1117 public void logrb(Level level, String sourceClass, String sourceMethod, 1118 String bundleName, String msg, Object param1) { 1119 if (!isLoggable(level)) { 1120 return; 1121 } 1122 LogRecord lr = new LogRecord(level, msg); 1123 lr.setSourceClassName(sourceClass); 1124 lr.setSourceMethodName(sourceMethod); 1125 Object params[] = { param1 }; 1126 lr.setParameters(params); 1127 doLog(lr, bundleName); 1128 } 1129 1130 /** 1131 * Log a message, specifying source class, method, and resource bundle name, 1132 * with an array of object arguments. 1133 * <p> 1134 * If the logger is currently enabled for the given message 1135 * level then a corresponding LogRecord is created and forwarded 1136 * to all the registered output Handler objects. 1137 * <p> 1138 * The msg string is localized using the named resource bundle. If the 1139 * resource bundle name is null, or an empty String or invalid 1140 * then the msg string is not localized. 1141 * <p> 1142 * @param level One of the message level identifiers, e.g., SEVERE 1143 * @param sourceClass name of class that issued the logging request 1144 * @param sourceMethod name of method that issued the logging request 1145 * @param bundleName name of resource bundle to localize msg, 1146 * can be null. 1147 * @param msg The string message (or a key in the message catalog) 1148 * @param params Array of parameters to the message 1149 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1150 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1151 * java.lang.Object...)} instead. 1152 */ 1153 @Deprecated 1154 public void logrb(Level level, String sourceClass, String sourceMethod, 1155 String bundleName, String msg, Object params[]) { 1156 if (!isLoggable(level)) { 1157 return; 1158 } 1159 LogRecord lr = new LogRecord(level, msg); 1160 lr.setSourceClassName(sourceClass); 1161 lr.setSourceMethodName(sourceMethod); 1162 lr.setParameters(params); 1163 doLog(lr, bundleName); 1164 } 1165 1166 /** 1167 * Log a message, specifying source class, method, and resource bundle, 1168 * with an optional list of message parameters. 1169 * <p> 1170 * If the logger is currently enabled for the given message 1171 * level then a corresponding LogRecord is created and forwarded 1172 * to all the registered output Handler objects. 1173 * <p> 1174 * The {@code msg} string is localized using the given resource bundle. 1175 * If the resource bundle is {@code null}, then the {@code msg} string is not 1176 * localized. 1177 * <p> 1178 * @param level One of the message level identifiers, e.g., SEVERE 1179 * @param sourceClass Name of the class that issued the logging request 1180 * @param sourceMethod Name of the method that issued the logging request 1181 * @param bundle Resource bundle to localize {@code msg}, 1182 * can be {@code null}. 1183 * @param msg The string message (or a key in the message catalog) 1184 * @param params Parameters to the message (optional, may be none). 1185 * @since 1.8 1186 */ 1187 public void logrb(Level level, String sourceClass, String sourceMethod, 1188 ResourceBundle bundle, String msg, Object... params) { 1189 if (!isLoggable(level)) { 1190 return; 1191 } 1192 LogRecord lr = new LogRecord(level, msg); 1193 lr.setSourceClassName(sourceClass); 1194 lr.setSourceMethodName(sourceMethod); 1195 if (params != null && params.length != 0) { 1196 lr.setParameters(params); 1197 } 1198 doLog(lr, bundle); 1199 } 1200 1201 /** 1202 * Log a message, specifying source class, method, and resource bundle name, 1203 * with associated Throwable information. 1204 * <p> 1205 * If the logger is currently enabled for the given message 1206 * level then the given arguments are stored in a LogRecord 1207 * which is forwarded to all registered output handlers. 1208 * <p> 1209 * The msg string is localized using the named resource bundle. If the 1210 * resource bundle name is null, or an empty String or invalid 1211 * then the msg string is not localized. 1212 * <p> 1213 * Note that the thrown argument is stored in the LogRecord thrown 1214 * property, rather than the LogRecord parameters property. Thus it is 1215 * processed specially by output Formatters and is not treated 1216 * as a formatting parameter to the LogRecord message property. 1217 * <p> 1218 * @param level One of the message level identifiers, e.g., SEVERE 1219 * @param sourceClass name of class that issued the logging request 1220 * @param sourceMethod name of method that issued the logging request 1221 * @param bundleName name of resource bundle to localize msg, 1222 * can be null 1223 * @param msg The string message (or a key in the message catalog) 1224 * @param thrown Throwable associated with log message. 1225 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1226 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1227 * java.lang.Throwable)} instead. 1228 */ 1229 @Deprecated 1230 public void logrb(Level level, String sourceClass, String sourceMethod, 1231 String bundleName, String msg, Throwable thrown) { 1232 if (!isLoggable(level)) { 1233 return; 1234 } 1235 LogRecord lr = new LogRecord(level, msg); 1236 lr.setSourceClassName(sourceClass); 1237 lr.setSourceMethodName(sourceMethod); 1238 lr.setThrown(thrown); 1239 doLog(lr, bundleName); 1240 } 1241 1242 /** 1243 * Log a message, specifying source class, method, and resource bundle, 1244 * with associated Throwable information. 1245 * <p> 1246 * If the logger is currently enabled for the given message 1247 * level then the given arguments are stored in a LogRecord 1248 * which is forwarded to all registered output handlers. 1249 * <p> 1250 * The {@code msg} string is localized using the given resource bundle. 1251 * If the resource bundle is {@code null}, then the {@code msg} string is not 1252 * localized. 1253 * <p> 1254 * Note that the thrown argument is stored in the LogRecord thrown 1255 * property, rather than the LogRecord parameters property. Thus it is 1256 * processed specially by output Formatters and is not treated 1257 * as a formatting parameter to the LogRecord message property. 1258 * <p> 1259 * @param level One of the message level identifiers, e.g., SEVERE 1260 * @param sourceClass Name of the class that issued the logging request 1261 * @param sourceMethod Name of the method that issued the logging request 1262 * @param bundle Resource bundle to localize {@code msg}, 1263 * can be {@code null} 1264 * @param msg The string message (or a key in the message catalog) 1265 * @param thrown Throwable associated with the log message. 1266 * @since 1.8 1267 */ 1268 public void logrb(Level level, String sourceClass, String sourceMethod, 1269 ResourceBundle bundle, String msg, Throwable thrown) { 1270 if (!isLoggable(level)) { 1271 return; 1272 } 1273 LogRecord lr = new LogRecord(level, msg); 1274 lr.setSourceClassName(sourceClass); 1275 lr.setSourceMethodName(sourceMethod); 1276 lr.setThrown(thrown); 1277 doLog(lr, bundle); 1278 } 1279 1280 //====================================================================== 1281 // Start of convenience methods for logging method entries and returns. 1282 //====================================================================== 1283 1284 /** 1285 * Log a method entry. 1286 * <p> 1287 * This is a convenience method that can be used to log entry 1288 * to a method. A LogRecord with message "ENTRY", log level 1289 * FINER, and the given sourceMethod and sourceClass is logged. 1290 * <p> 1291 * @param sourceClass name of class that issued the logging request 1292 * @param sourceMethod name of method that is being entered 1293 */ 1294 public void entering(String sourceClass, String sourceMethod) { 1295 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); 1296 } 1297 1298 /** 1299 * Log a method entry, with one parameter. 1300 * <p> 1301 * This is a convenience method that can be used to log entry 1302 * to a method. A LogRecord with message "ENTRY {0}", log level 1303 * FINER, and the given sourceMethod, sourceClass, and parameter 1304 * is logged. 1305 * <p> 1306 * @param sourceClass name of class that issued the logging request 1307 * @param sourceMethod name of method that is being entered 1308 * @param param1 parameter to the method being entered 1309 */ 1310 public void entering(String sourceClass, String sourceMethod, Object param1) { 1311 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1); 1312 } 1313 1314 /** 1315 * Log a method entry, with an array of parameters. 1316 * <p> 1317 * This is a convenience method that can be used to log entry 1318 * to a method. A LogRecord with message "ENTRY" (followed by a 1319 * format {N} indicator for each entry in the parameter array), 1320 * log level FINER, and the given sourceMethod, sourceClass, and 1321 * parameters is logged. 1322 * <p> 1323 * @param sourceClass name of class that issued the logging request 1324 * @param sourceMethod name of method that is being entered 1325 * @param params array of parameters to the method being entered 1326 */ 1327 public void entering(String sourceClass, String sourceMethod, Object params[]) { 1328 String msg = "ENTRY"; 1329 if (params == null ) { 1330 logp(Level.FINER, sourceClass, sourceMethod, msg); 1331 return; 1332 } 1333 if (!isLoggable(Level.FINER)) return; 1334 for (int i = 0; i < params.length; i++) { 1335 msg = msg + " {" + i + "}"; 1336 } 1337 logp(Level.FINER, sourceClass, sourceMethod, msg, params); 1338 } 1339 1340 /** 1341 * Log a method return. 1342 * <p> 1343 * This is a convenience method that can be used to log returning 1344 * from a method. A LogRecord with message "RETURN", log level 1345 * FINER, and the given sourceMethod and sourceClass is logged. 1346 * <p> 1347 * @param sourceClass name of class that issued the logging request 1348 * @param sourceMethod name of the method 1349 */ 1350 public void exiting(String sourceClass, String sourceMethod) { 1351 logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); 1352 } 1353 1354 1355 /** 1356 * Log a method return, with result object. 1357 * <p> 1358 * This is a convenience method that can be used to log returning 1359 * from a method. A LogRecord with message "RETURN {0}", log level 1360 * FINER, and the gives sourceMethod, sourceClass, and result 1361 * object is logged. 1362 * <p> 1363 * @param sourceClass name of class that issued the logging request 1364 * @param sourceMethod name of the method 1365 * @param result Object that is being returned 1366 */ 1367 public void exiting(String sourceClass, String sourceMethod, Object result) { 1368 logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); 1369 } 1370 1371 /** 1372 * Log throwing an exception. 1373 * <p> 1374 * This is a convenience method to log that a method is 1375 * terminating by throwing an exception. The logging is done 1376 * using the FINER level. 1377 * <p> 1378 * If the logger is currently enabled for the given message 1379 * level then the given arguments are stored in a LogRecord 1380 * which is forwarded to all registered output handlers. The 1381 * LogRecord's message is set to "THROW". 1382 * <p> 1383 * Note that the thrown argument is stored in the LogRecord thrown 1384 * property, rather than the LogRecord parameters property. Thus it is 1385 * processed specially by output Formatters and is not treated 1386 * as a formatting parameter to the LogRecord message property. 1387 * <p> 1388 * @param sourceClass name of class that issued the logging request 1389 * @param sourceMethod name of the method. 1390 * @param thrown The Throwable that is being thrown. 1391 */ 1392 public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { 1393 if (!isLoggable(Level.FINER)) { 1394 return; 1395 } 1396 LogRecord lr = new LogRecord(Level.FINER, "THROW"); 1397 lr.setSourceClassName(sourceClass); 1398 lr.setSourceMethodName(sourceMethod); 1399 lr.setThrown(thrown); 1400 doLog(lr); 1401 } 1402 1403 //======================================================================= 1404 // Start of simple convenience methods using level names as method names 1405 //======================================================================= 1406 1407 /** 1408 * Log a SEVERE message. 1409 * <p> 1410 * If the logger is currently enabled for the SEVERE message 1411 * level then the given message is forwarded to all the 1412 * registered output Handler objects. 1413 * <p> 1414 * @param msg The string message (or a key in the message catalog) 1415 */ 1416 public void severe(String msg) { 1417 log(Level.SEVERE, msg); 1418 } 1419 1420 /** 1421 * Log a WARNING message. 1422 * <p> 1423 * If the logger is currently enabled for the WARNING message 1424 * level then the given message is forwarded to all the 1425 * registered output Handler objects. 1426 * <p> 1427 * @param msg The string message (or a key in the message catalog) 1428 */ 1429 public void warning(String msg) { 1430 log(Level.WARNING, msg); 1431 } 1432 1433 /** 1434 * Log an INFO message. 1435 * <p> 1436 * If the logger is currently enabled for the INFO message 1437 * level then the given message is forwarded to all the 1438 * registered output Handler objects. 1439 * <p> 1440 * @param msg The string message (or a key in the message catalog) 1441 */ 1442 public void info(String msg) { 1443 log(Level.INFO, msg); 1444 } 1445 1446 /** 1447 * Log a CONFIG message. 1448 * <p> 1449 * If the logger is currently enabled for the CONFIG message 1450 * level then the given message is forwarded to all the 1451 * registered output Handler objects. 1452 * <p> 1453 * @param msg The string message (or a key in the message catalog) 1454 */ 1455 public void config(String msg) { 1456 log(Level.CONFIG, msg); 1457 } 1458 1459 /** 1460 * Log a FINE message. 1461 * <p> 1462 * If the logger is currently enabled for the FINE message 1463 * level then the given message is forwarded to all the 1464 * registered output Handler objects. 1465 * <p> 1466 * @param msg The string message (or a key in the message catalog) 1467 */ 1468 public void fine(String msg) { 1469 log(Level.FINE, msg); 1470 } 1471 1472 /** 1473 * Log a FINER message. 1474 * <p> 1475 * If the logger is currently enabled for the FINER message 1476 * level then the given message is forwarded to all the 1477 * registered output Handler objects. 1478 * <p> 1479 * @param msg The string message (or a key in the message catalog) 1480 */ 1481 public void finer(String msg) { 1482 log(Level.FINER, msg); 1483 } 1484 1485 /** 1486 * Log a FINEST message. 1487 * <p> 1488 * If the logger is currently enabled for the FINEST message 1489 * level then the given message is forwarded to all the 1490 * registered output Handler objects. 1491 * <p> 1492 * @param msg The string message (or a key in the message catalog) 1493 */ 1494 public void finest(String msg) { 1495 log(Level.FINEST, msg); 1496 } 1497 1498 //======================================================================= 1499 // Start of simple convenience methods using level names as method names 1500 // and use Supplier<String> 1501 //======================================================================= 1502 1503 /** 1504 * Log a SEVERE message, which is only to be constructed if the logging 1505 * level is such that the message will actually be logged. 1506 * <p> 1507 * If the logger is currently enabled for the SEVERE message 1508 * level then the message is constructed by invoking the provided 1509 * supplier function and forwarded to all the registered output 1510 * Handler objects. 1511 * <p> 1512 * @param msgSupplier A function, which when called, produces the 1513 * desired log message 1514 * @since 1.8 1515 */ 1516 public void severe(Supplier<String> msgSupplier) { 1517 log(Level.SEVERE, msgSupplier); 1518 } 1519 1520 /** 1521 * Log a WARNING message, which is only to be constructed if the logging 1522 * level is such that the message will actually be logged. 1523 * <p> 1524 * If the logger is currently enabled for the WARNING message 1525 * level then the message is constructed by invoking the provided 1526 * supplier function and forwarded to all the registered output 1527 * Handler objects. 1528 * <p> 1529 * @param msgSupplier A function, which when called, produces the 1530 * desired log message 1531 * @since 1.8 1532 */ 1533 public void warning(Supplier<String> msgSupplier) { 1534 log(Level.WARNING, msgSupplier); 1535 } 1536 1537 /** 1538 * Log a INFO message, which is only to be constructed if the logging 1539 * level is such that the message will actually be logged. 1540 * <p> 1541 * If the logger is currently enabled for the INFO message 1542 * level then the message is constructed by invoking the provided 1543 * supplier function and forwarded to all the registered output 1544 * Handler objects. 1545 * <p> 1546 * @param msgSupplier A function, which when called, produces the 1547 * desired log message 1548 * @since 1.8 1549 */ 1550 public void info(Supplier<String> msgSupplier) { 1551 log(Level.INFO, msgSupplier); 1552 } 1553 1554 /** 1555 * Log a CONFIG message, which is only to be constructed if the logging 1556 * level is such that the message will actually be logged. 1557 * <p> 1558 * If the logger is currently enabled for the CONFIG message 1559 * level then the message is constructed by invoking the provided 1560 * supplier function and forwarded to all the registered output 1561 * Handler objects. 1562 * <p> 1563 * @param msgSupplier A function, which when called, produces the 1564 * desired log message 1565 * @since 1.8 1566 */ 1567 public void config(Supplier<String> msgSupplier) { 1568 log(Level.CONFIG, msgSupplier); 1569 } 1570 1571 /** 1572 * Log a FINE message, which is only to be constructed if the logging 1573 * level is such that the message will actually be logged. 1574 * <p> 1575 * If the logger is currently enabled for the FINE message 1576 * level then the message is constructed by invoking the provided 1577 * supplier function and forwarded to all the registered output 1578 * Handler objects. 1579 * <p> 1580 * @param msgSupplier A function, which when called, produces the 1581 * desired log message 1582 * @since 1.8 1583 */ 1584 public void fine(Supplier<String> msgSupplier) { 1585 log(Level.FINE, msgSupplier); 1586 } 1587 1588 /** 1589 * Log a FINER message, which is only to be constructed if the logging 1590 * level is such that the message will actually be logged. 1591 * <p> 1592 * If the logger is currently enabled for the FINER message 1593 * level then the message is constructed by invoking the provided 1594 * supplier function and forwarded to all the registered output 1595 * Handler objects. 1596 * <p> 1597 * @param msgSupplier A function, which when called, produces the 1598 * desired log message 1599 * @since 1.8 1600 */ 1601 public void finer(Supplier<String> msgSupplier) { 1602 log(Level.FINER, msgSupplier); 1603 } 1604 1605 /** 1606 * Log a FINEST message, which is only to be constructed if the logging 1607 * level is such that the message will actually be logged. 1608 * <p> 1609 * If the logger is currently enabled for the FINEST message 1610 * level then the message is constructed by invoking the provided 1611 * supplier function and forwarded to all the registered output 1612 * Handler objects. 1613 * <p> 1614 * @param msgSupplier A function, which when called, produces the 1615 * desired log message 1616 * @since 1.8 1617 */ 1618 public void finest(Supplier<String> msgSupplier) { 1619 log(Level.FINEST, msgSupplier); 1620 } 1621 1622 //================================================================ 1623 // End of convenience methods 1624 //================================================================ 1625 1626 /** 1627 * Set the log level specifying which message levels will be 1628 * logged by this logger. Message levels lower than this 1629 * value will be discarded. The level value Level.OFF 1630 * can be used to turn off logging. 1631 * <p> 1632 * If the new level is null, it means that this node should 1633 * inherit its level from its nearest ancestor with a specific 1634 * (non-null) level value. 1635 * 1636 * @param newLevel the new value for the log level (may be null) 1637 * @throws SecurityException if a security manager exists, 1638 * this logger is not anonymous, and the caller 1639 * does not have LoggingPermission("control"). 1640 */ 1641 public void setLevel(Level newLevel) throws SecurityException { 1642 checkPermission(); 1643 synchronized (treeLock) { 1644 levelObject = newLevel; 1645 updateEffectiveLevel(); 1646 } 1647 } 1648 1649 final boolean isLevelInitialized() { 1650 return levelObject != null; 1651 } 1652 1653 /** 1654 * Get the log Level that has been specified for this Logger. 1655 * The result may be null, which means that this logger's 1656 * effective level will be inherited from its parent. 1657 * 1658 * @return this Logger's level 1659 */ 1660 public Level getLevel() { 1661 return levelObject; 1662 } 1663 1664 /** 1665 * Check if a message of the given level would actually be logged 1666 * by this logger. This check is based on the Loggers effective level, 1667 * which may be inherited from its parent. 1668 * 1669 * @param level a message logging level 1670 * @return true if the given message level is currently being logged. 1671 */ 1672 public boolean isLoggable(Level level) { 1673 if (level.intValue() < levelValue || levelValue == offValue) { 1674 return false; 1675 } 1676 return true; 1677 } 1678 1679 /** 1680 * Get the name for this logger. 1681 * @return logger name. Will be null for anonymous Loggers. 1682 */ 1683 public String getName() { 1684 return name; 1685 } 1686 1687 /** 1688 * Add a log Handler to receive logging messages. 1689 * <p> 1690 * By default, Loggers also send their output to their parent logger. 1691 * Typically the root Logger is configured with a set of Handlers 1692 * that essentially act as default handlers for all loggers. 1693 * 1694 * @param handler a logging Handler 1695 * @throws SecurityException if a security manager exists, 1696 * this logger is not anonymous, and the caller 1697 * does not have LoggingPermission("control"). 1698 */ 1699 public void addHandler(Handler handler) throws SecurityException { 1700 // Check for null handler 1701 handler.getClass(); 1702 checkPermission(); 1703 handlers.add(handler); 1704 } 1705 1706 /** 1707 * Remove a log Handler. 1708 * <P> 1709 * Returns silently if the given Handler is not found or is null 1710 * 1711 * @param handler a logging Handler 1712 * @throws SecurityException if a security manager exists, 1713 * this logger is not anonymous, and the caller 1714 * does not have LoggingPermission("control"). 1715 */ 1716 public void removeHandler(Handler handler) throws SecurityException { 1717 checkPermission(); 1718 if (handler == null) { 1719 return; 1720 } 1721 handlers.remove(handler); 1722 } 1723 1724 /** 1725 * Get the Handlers associated with this logger. 1726 * <p> 1727 * @return an array of all registered Handlers 1728 */ 1729 public Handler[] getHandlers() { 1730 return handlers.toArray(emptyHandlers); 1731 } 1732 1733 /** 1734 * Specify whether or not this logger should send its output 1735 * to its parent Logger. This means that any LogRecords will 1736 * also be written to the parent's Handlers, and potentially 1737 * to its parent, recursively up the namespace. 1738 * 1739 * @param useParentHandlers true if output is to be sent to the 1740 * logger's parent. 1741 * @throws SecurityException if a security manager exists, 1742 * this logger is not anonymous, and the caller 1743 * does not have LoggingPermission("control"). 1744 */ 1745 public void setUseParentHandlers(boolean useParentHandlers) { 1746 checkPermission(); 1747 this.useParentHandlers = useParentHandlers; 1748 } 1749 1750 /** 1751 * Discover whether or not this logger is sending its output 1752 * to its parent logger. 1753 * 1754 * @return true if output is to be sent to the logger's parent 1755 */ 1756 public boolean getUseParentHandlers() { 1757 return useParentHandlers; 1758 } 1759 1760 static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; 1761 1762 private static ResourceBundle findSystemResourceBundle(final Locale locale) { 1763 // the resource bundle is in a restricted package 1764 return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() { 1765 @Override 1766 public ResourceBundle run() { 1767 try { 1768 return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, 1769 locale, 1770 ClassLoader.getSystemClassLoader()); 1771 } catch (MissingResourceException e) { 1772 throw new InternalError(e.toString()); 1773 } 1774 } 1775 }); 1776 } 1777 1778 /** 1779 * Private utility method to map a resource bundle name to an 1780 * actual resource bundle, using a simple one-entry cache. 1781 * Returns null for a null name. 1782 * May also return null if we can't find the resource bundle and 1783 * there is no suitable previous cached value. 1784 * 1785 * @param name the ResourceBundle to locate 1786 * @param userCallersClassLoader if true search using the caller's ClassLoader 1787 * @return ResourceBundle specified by name or null if not found 1788 */ 1789 private synchronized ResourceBundle findResourceBundle(String name, 1790 boolean useCallersClassLoader) { 1791 // For all lookups, we first check the thread context class loader 1792 // if it is set. If not, we use the system classloader. If we 1793 // still haven't found it we use the callersClassLoaderRef if it 1794 // is set and useCallersClassLoader is true. We set 1795 // callersClassLoaderRef initially upon creating the logger with a 1796 // non-null resource bundle name. 1797 1798 // Return a null bundle for a null name. 1799 if (name == null) { 1800 return null; 1801 } 1802 1803 Locale currentLocale = Locale.getDefault(); 1804 1805 // Normally we should hit on our simple one entry cache. 1806 if (userBundle != null && 1807 name.equals(resourceBundleName)) { 1808 return userBundle; 1809 } else if (catalog != null && currentLocale.equals(catalogLocale) 1810 && name.equals(catalogName)) { 1811 return catalog; 1812 } 1813 1814 if (name.equals(SYSTEM_LOGGER_RB_NAME)) { 1815 catalog = findSystemResourceBundle(currentLocale); 1816 catalogName = name; 1817 catalogLocale = currentLocale; 1818 return catalog; 1819 } 1820 1821 // Use the thread's context ClassLoader. If there isn't one, use the 1822 // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}. 1823 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1824 if (cl == null) { 1825 cl = ClassLoader.getSystemClassLoader(); 1826 } 1827 try { 1828 catalog = ResourceBundle.getBundle(name, currentLocale, cl); 1829 catalogName = name; 1830 catalogLocale = currentLocale; 1831 return catalog; 1832 } catch (MissingResourceException ex) { 1833 // We can't find the ResourceBundle in the default 1834 // ClassLoader. Drop through. 1835 } 1836 1837 if (useCallersClassLoader) { 1838 // Try with the caller's ClassLoader 1839 ClassLoader callersClassLoader = getCallersClassLoader(); 1840 1841 if (callersClassLoader == null || callersClassLoader == cl) { 1842 return null; 1843 } 1844 1845 try { 1846 catalog = ResourceBundle.getBundle(name, currentLocale, 1847 callersClassLoader); 1848 catalogName = name; 1849 catalogLocale = currentLocale; 1850 return catalog; 1851 } catch (MissingResourceException ex) { 1852 return null; // no luck 1853 } 1854 } else { 1855 return null; 1856 } 1857 } 1858 1859 // Private utility method to initialize our one entry 1860 // resource bundle name cache and the callers ClassLoader 1861 // Note: for consistency reasons, we are careful to check 1862 // that a suitable ResourceBundle exists before setting the 1863 // resourceBundleName field. 1864 // Synchronized to prevent races in setting the fields. 1865 private synchronized void setupResourceInfo(String name, 1866 Class<?> callersClass) { 1867 if (resourceBundleName != null) { 1868 // this Logger already has a ResourceBundle 1869 1870 if (resourceBundleName.equals(name)) { 1871 // the names match so there is nothing more to do 1872 return; 1873 } 1874 1875 // cannot change ResourceBundles once they are set 1876 throw new IllegalArgumentException( 1877 resourceBundleName + " != " + name); 1878 } 1879 1880 if (name == null) { 1881 return; 1882 } 1883 1884 setCallersClassLoaderRef(callersClass); 1885 if (findResourceBundle(name, true) == null) { 1886 // We've failed to find an expected ResourceBundle. 1887 // unset the caller's ClassLoader since we were unable to find the 1888 // the bundle using it 1889 this.callersClassLoaderRef = null; 1890 throw new MissingResourceException("Can't find " + name + " bundle", 1891 name, ""); 1892 } 1893 resourceBundleName = name; 1894 } 1895 1896 /** 1897 * Sets a resource bundle on this logger. 1898 * All messages will be logged using the given resource bundle for its 1899 * specific {@linkplain ResourceBundle#getLocale locale}. 1900 * @param bundle The resource bundle that this logger shall use. 1901 * @throws NullPointerException if the given bundle is {@code null}. 1902 * @throws IllegalArgumentException if the given bundle doesn't have a 1903 * {@linkplain ResourceBundle#getBaseBundleName base name}, 1904 * or if this logger already has a resource bundle set but 1905 * the given bundle has a different base name. 1906 * @throws SecurityException if a security manager exists, 1907 * this logger is not anonymous, and the caller 1908 * does not have LoggingPermission("control"). 1909 * @since 1.8 1910 */ 1911 public void setResourceBundle(ResourceBundle bundle) { 1912 checkPermission(); 1913 1914 // Will throw NPE if bundle is null. 1915 final String baseName = bundle.getBaseBundleName(); 1916 1917 // bundle must have a name 1918 if (baseName == null || baseName.isEmpty()) { 1919 throw new IllegalArgumentException("resource bundle must have a name"); 1920 } 1921 1922 synchronized (this) { 1923 final boolean canReplaceResourceBundle = resourceBundleName == null 1924 || resourceBundleName.equals(baseName); 1925 1926 if (!canReplaceResourceBundle) { 1927 throw new IllegalArgumentException("can't replace resource bundle"); 1928 } 1929 1930 1931 userBundle = bundle; 1932 resourceBundleName = baseName; 1933 } 1934 } 1935 1936 /** 1937 * Return the parent for this Logger. 1938 * <p> 1939 * This method returns the nearest extant parent in the namespace. 1940 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b" 1941 * has been created but no logger "a.b.c" exists, then a call of 1942 * getParent on the Logger "a.b.c.d" will return the Logger "a.b". 1943 * <p> 1944 * The result will be null if it is called on the root Logger 1945 * in the namespace. 1946 * 1947 * @return nearest existing parent Logger 1948 */ 1949 public Logger getParent() { 1950 // Note: this used to be synchronized on treeLock. However, this only 1951 // provided memory semantics, as there was no guarantee that the caller 1952 // would synchronize on treeLock (in fact, there is no way for external 1953 // callers to so synchronize). Therefore, we have made parent volatile 1954 // instead. 1955 return parent; 1956 } 1957 1958 /** 1959 * Set the parent for this Logger. This method is used by 1960 * the LogManager to update a Logger when the namespace changes. 1961 * <p> 1962 * It should not be called from application code. 1963 * <p> 1964 * @param parent the new parent logger 1965 * @throws SecurityException if a security manager exists and if 1966 * the caller does not have LoggingPermission("control"). 1967 */ 1968 public void setParent(Logger parent) { 1969 if (parent == null) { 1970 throw new NullPointerException(); 1971 } 1972 1973 // check permission for all loggers, including anonymous loggers 1974 if (manager == null) { 1975 manager = LogManager.getLogManager(); 1976 } 1977 manager.checkPermission(); 1978 1979 doSetParent(parent); 1980 } 1981 1982 // Private method to do the work for parenting a child 1983 // Logger onto a parent logger. 1984 private void doSetParent(Logger newParent) { 1985 1986 // System.err.println("doSetParent \"" + getName() + "\" \"" 1987 // + newParent.getName() + "\""); 1988 1989 synchronized (treeLock) { 1990 1991 // Remove ourself from any previous parent. 1992 LogManager.LoggerWeakRef ref = null; 1993 if (parent != null) { 1994 // assert parent.kids != null; 1995 for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) { 1996 ref = iter.next(); 1997 Logger kid = ref.get(); 1998 if (kid == this) { 1999 // ref is used down below to complete the reparenting 2000 iter.remove(); 2001 break; 2002 } else { 2003 ref = null; 2004 } 2005 } 2006 // We have now removed ourself from our parents' kids. 2007 } 2008 2009 // Set our new parent. 2010 parent = newParent; 2011 if (parent.kids == null) { 2012 parent.kids = new ArrayList<>(2); 2013 } 2014 if (ref == null) { 2015 // we didn't have a previous parent 2016 ref = manager.new LoggerWeakRef(this); 2017 } 2018 ref.setParentRef(new WeakReference<>(parent)); 2019 parent.kids.add(ref); 2020 2021 // As a result of the reparenting, the effective level 2022 // may have changed for us and our children. 2023 updateEffectiveLevel(); 2024 2025 } 2026 } 2027 2028 // Package-level method. 2029 // Remove the weak reference for the specified child Logger from the 2030 // kid list. We should only be called from LoggerWeakRef.dispose(). 2031 final void removeChildLogger(LogManager.LoggerWeakRef child) { 2032 synchronized (treeLock) { 2033 for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) { 2034 LogManager.LoggerWeakRef ref = iter.next(); 2035 if (ref == child) { 2036 iter.remove(); 2037 return; 2038 } 2039 } 2040 } 2041 } 2042 2043 // Recalculate the effective level for this node and 2044 // recursively for our children. 2045 2046 private void updateEffectiveLevel() { 2047 // assert Thread.holdsLock(treeLock); 2048 2049 // Figure out our current effective level. 2050 int newLevelValue; 2051 if (levelObject != null) { 2052 newLevelValue = levelObject.intValue(); 2053 } else { 2054 if (parent != null) { 2055 newLevelValue = parent.levelValue; 2056 } else { 2057 // This may happen during initialization. 2058 newLevelValue = Level.INFO.intValue(); 2059 } 2060 } 2061 2062 // If our effective value hasn't changed, we're done. 2063 if (levelValue == newLevelValue) { 2064 return; 2065 } 2066 2067 levelValue = newLevelValue; 2068 2069 // System.err.println("effective level: \"" + getName() + "\" := " + level); 2070 2071 // Recursively update the level on each of our kids. 2072 if (kids != null) { 2073 for (int i = 0; i < kids.size(); i++) { 2074 LogManager.LoggerWeakRef ref = kids.get(i); 2075 Logger kid = ref.get(); 2076 if (kid != null) { 2077 kid.updateEffectiveLevel(); 2078 } 2079 } 2080 } 2081 } 2082 2083 2084 // Private method to get the potentially inherited 2085 // resource bundle name for this Logger. 2086 // May return null 2087 private String getEffectiveResourceBundleName() { 2088 Logger target = this; 2089 while (target != null) { 2090 String rbn = target.getResourceBundleName(); 2091 if (rbn != null) { 2092 return rbn; 2093 } 2094 target = target.getParent(); 2095 } 2096 return null; 2097 } 2098 2099 2100 private ResourceBundle getEffectiveResourceBundle() { 2101 Logger target = this; 2102 if (SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName)) return null; 2103 ResourceBundle localRB = getResourceBundle(); 2104 if (localRB != null) { 2105 return localRB; 2106 } 2107 2108 while (target != null) { 2109 final ResourceBundle rb = target.userBundle; 2110 if (rb != null) { 2111 return rb; 2112 } 2113 final String rbn = target.getResourceBundleName(); 2114 if (rbn != null) { 2115 if (!SYSTEM_LOGGER_RB_NAME.equals(rbn)) { 2116 return findResourceBundle(rbn, true); 2117 } else { 2118 return null; 2119 } 2120 } 2121 target = target.getParent(); 2122 } 2123 return null; 2124 } 2125 2126 }