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