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