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