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