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