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