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