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