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