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