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