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