1 /* 2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package java.util.logging; 28 29 import java.lang.ref.WeakReference; 30 import java.lang.reflect.Module; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.ArrayList; 34 import java.util.Iterator; 35 import java.util.Locale; 36 import java.util.MissingResourceException; 37 import java.util.Objects; 38 import java.util.ResourceBundle; 39 import java.util.concurrent.CopyOnWriteArrayList; 40 import java.util.function.Supplier; 41 42 import jdk.internal.misc.JavaUtilResourceBundleAccess; 43 import jdk.internal.misc.SharedSecrets; 44 import jdk.internal.reflect.CallerSensitive; 45 import jdk.internal.reflect.Reflection; 46 import static jdk.internal.logger.DefaultLoggerFinder.isSystem; 47 48 /** 49 * A Logger object is used to log messages for a specific 50 * system or application component. Loggers are normally named, 51 * using a hierarchical dot-separated namespace. Logger names 52 * can be arbitrary strings, but they should normally be based on 53 * the package name or class name of the logged component, such 54 * as java.net or javax.swing. In addition it is possible to create 55 * "anonymous" Loggers that are not stored in the Logger namespace. 56 * <p> 57 * Logger objects may be obtained by calls on one of the getLogger 58 * factory methods. These will either create a new Logger or 59 * return a suitable existing Logger. It is important to note that 60 * the Logger returned by one of the {@code getLogger} factory methods 61 * may be garbage collected at any time if a strong reference to the 62 * Logger is not kept. 63 * <p> 64 * Logging messages will be forwarded to registered Handler 65 * objects, which can forward the messages to a variety of 66 * destinations, including consoles, files, OS logs, etc. 67 * <p> 68 * Each Logger keeps track of a "parent" Logger, which is its 69 * nearest existing ancestor in the Logger namespace. 70 * <p> 71 * Each Logger has a "Level" associated with it. This reflects 72 * a minimum Level that this logger cares about. If a Logger's 73 * level is set to {@code null}, then its effective level is inherited 74 * from its parent, which may in turn obtain it recursively from its 75 * parent, and so on up the tree. 76 * <p> 77 * The log level can be configured based on the properties from the 78 * logging configuration file, as described in the description 79 * of the LogManager class. However it may also be dynamically changed 80 * by calls on the Logger.setLevel method. If a logger's level is 81 * changed the change may also affect child loggers, since any child 82 * logger that has {@code null} as its level will inherit its 83 * effective level from its parent. 84 * <p> 85 * On each logging call the Logger initially performs a cheap 86 * check of the request level (e.g., SEVERE or FINE) against the 87 * effective log level of the logger. If the request level is 88 * lower than the log level, the logging call returns immediately. 89 * <p> 90 * After passing this initial (cheap) test, the Logger will allocate 91 * a LogRecord to describe the logging message. It will then call a 92 * Filter (if present) to do a more detailed check on whether the 93 * record should be published. If that passes it will then publish 94 * the LogRecord to its output Handlers. By default, loggers also 95 * publish to their parent's Handlers, recursively up the tree. 96 * <p> 97 * Each Logger may have a {@code ResourceBundle} associated with it. 98 * The {@code ResourceBundle} may be specified by name, using the 99 * {@link #getLogger(java.lang.String, java.lang.String)} factory 100 * method, or by value - using the {@link 101 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 102 * This bundle will be used for localizing logging messages. 103 * If a Logger does not have its own {@code ResourceBundle} or resource bundle 104 * name, then it will inherit the {@code ResourceBundle} or resource bundle name 105 * from its parent, recursively up the tree. 106 * <p> 107 * Most of the logger output methods take a "msg" argument. This 108 * msg argument may be either a raw value or a localization key. 109 * During formatting, if the logger has (or inherits) a localization 110 * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for 111 * the msg string, then the msg string is replaced by the localized value. 112 * Otherwise the original msg string is used. Typically, formatters use 113 * java.text.MessageFormat style formatting to format parameters, so 114 * for example a format string "{0} {1}" would format two parameters 115 * as strings. 116 * <p> 117 * A set of methods alternatively take a "msgSupplier" instead of a "msg" 118 * argument. These methods take a {@link Supplier}{@code <String>} function 119 * which is invoked to construct the desired log message only when the message 120 * actually is to be logged based on the effective log level thus eliminating 121 * unnecessary message construction. For example, if the developer wants to 122 * log system health status for diagnosis, with the String-accepting version, 123 * the code would look like: 124 * <pre>{@code 125 * 126 * class DiagnosisMessages { 127 * static String systemHealthStatus() { 128 * // collect system health information 129 * ... 130 * } 131 * } 132 * ... 133 * logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus()); 134 * }</pre> 135 * With the above code, the health status is collected unnecessarily even when 136 * the log level FINER is disabled. With the Supplier-accepting version as 137 * below, the status will only be collected when the log level FINER is 138 * enabled. 139 * <pre>{@code 140 * 141 * logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus); 142 * }</pre> 143 * <p> 144 * When looking for a {@code ResourceBundle}, the logger will first look at 145 * whether a bundle was specified using {@link 146 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then 147 * only whether a resource bundle name was specified through the {@link 148 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 149 * If no {@code ResourceBundle} or no resource bundle name is found, 150 * then it will use the nearest {@code ResourceBundle} or resource bundle 151 * name inherited from its parent tree.<br> 152 * When a {@code ResourceBundle} was inherited or specified through the 153 * {@link 154 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then 155 * that {@code ResourceBundle} will be used. Otherwise if the logger only 156 * has or inherited a resource bundle name, then that resource bundle name 157 * will be mapped to a {@code ResourceBundle} object, using the default Locale 158 * at the time of logging. 159 * <br id="ResourceBundleMapping">When mapping resource bundle names to 160 * {@code ResourceBundle} objects, the logger will first try to use the 161 * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class 162 * loader} to map the given resource bundle name to a {@code ResourceBundle}. 163 * If the thread context class loader is {@code null}, it will try the 164 * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader} 165 * instead. If the {@code ResourceBundle} is still not found, it will use the 166 * class loader of the first caller of the {@link 167 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 168 * <p> 169 * Formatting (including localization) is the responsibility of 170 * the output Handler, which will typically call a Formatter. 171 * <p> 172 * Note that formatting need not occur synchronously. It may be delayed 173 * until a LogRecord is actually written to an external sink. 174 * <p> 175 * The logging methods are grouped in five main categories: 176 * <ul> 177 * <li><p> 178 * There are a set of "log" methods that take a log level, a message 179 * string, and optionally some parameters to the message string. 180 * <li><p> 181 * There are a set of "logp" methods (for "log precise") that are 182 * like the "log" methods, but also take an explicit source class name 183 * and method name. 184 * <li><p> 185 * There are a set of "logrb" method (for "log with resource bundle") 186 * that are like the "logp" method, but also take an explicit resource 187 * bundle object for use in localizing the log message. 188 * <li><p> 189 * There are convenience methods for tracing method entries (the 190 * "entering" methods), method returns (the "exiting" methods) and 191 * throwing exceptions (the "throwing" methods). 192 * <li><p> 193 * Finally, there are a set of convenience methods for use in the 194 * very simplest cases, when a developer simply wants to log a 195 * simple string at a given log level. These methods are named 196 * after the standard Level names ("severe", "warning", "info", etc.) 197 * and take a single argument, a message string. 198 * </ul> 199 * <p> 200 * For the methods that do not take an explicit source name and 201 * method name, the Logging framework will make a "best effort" 202 * to determine which class and method called into the logging method. 203 * However, it is important to realize that this automatically inferred 204 * information may only be approximate (or may even be quite wrong!). 205 * Virtual machines are allowed to do extensive optimizations when 206 * JITing and may entirely remove stack frames, making it impossible 207 * to reliably locate the calling class and method. 208 * <P> 209 * All methods on Logger are multi-thread safe. 210 * <p> 211 * <b>Subclassing Information:</b> Note that a LogManager class may 212 * provide its own implementation of named Loggers for any point in 213 * the namespace. Therefore, any subclasses of Logger (unless they 214 * are implemented in conjunction with a new LogManager class) should 215 * take care to obtain a Logger instance from the LogManager class and 216 * should delegate operations such as "isLoggable" and "log(LogRecord)" 217 * to that instance. Note that in order to intercept all logging 218 * output, subclasses need only override the log(LogRecord) method. 219 * All the other logging methods are implemented as calls on this 220 * log(LogRecord) method. 221 * 222 * @since 1.4 223 */ 224 public class Logger { 225 private static final Handler emptyHandlers[] = new Handler[0]; 226 private static final int offValue = Level.OFF.intValue(); 227 228 static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; 229 230 // This class is immutable and it is important that it remains so. 231 private static final class LoggerBundle { 232 final String resourceBundleName; // Base name of the bundle. 233 final ResourceBundle userBundle; // Bundle set through setResourceBundle. 234 private LoggerBundle(String resourceBundleName, ResourceBundle bundle) { 235 this.resourceBundleName = resourceBundleName; 236 this.userBundle = bundle; 237 } 238 boolean isSystemBundle() { 239 return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName); 240 } 241 static LoggerBundle get(String name, ResourceBundle bundle) { 242 if (name == null && bundle == null) { 243 return NO_RESOURCE_BUNDLE; 244 } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) { 245 return SYSTEM_BUNDLE; 246 } else { 247 return new LoggerBundle(name, bundle); 248 } 249 } 250 } 251 252 // This instance will be shared by all loggers created by the system 253 // code 254 private static final LoggerBundle SYSTEM_BUNDLE = 255 new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null); 256 257 // This instance indicates that no resource bundle has been specified yet, 258 // and it will be shared by all loggers which have no resource bundle. 259 private static final LoggerBundle NO_RESOURCE_BUNDLE = 260 new LoggerBundle(null, null); 261 262 // Calling SharedSecrets.getJavaUtilResourceBundleAccess() 263 // forces the initialization of ResourceBundle.class, which 264 // can be too early if the VM has not finished booting yet. 265 private static final class RbAccess { 266 static final JavaUtilResourceBundleAccess RB_ACCESS = 267 SharedSecrets.getJavaUtilResourceBundleAccess(); 268 } 269 270 // A value class that holds the logger configuration data. 271 // This configuration can be shared between an application logger 272 // and a system logger of the same name. 273 private static final class ConfigurationData { 274 275 // The delegate field is used to avoid races while 276 // merging configuration. This will ensure that any pending 277 // configuration action on an application logger will either 278 // be finished before the merge happens, or will be forwarded 279 // to the system logger configuration after the merge is completed. 280 // By default delegate=this. 281 private volatile ConfigurationData delegate; 282 283 volatile boolean useParentHandlers; 284 volatile Filter filter; 285 volatile Level levelObject; 286 volatile int levelValue; // current effective level value 287 final CopyOnWriteArrayList<Handler> handlers = 288 new CopyOnWriteArrayList<>(); 289 290 ConfigurationData() { 291 delegate = this; 292 useParentHandlers = true; 293 levelValue = Level.INFO.intValue(); 294 } 295 296 void setUseParentHandlers(boolean flag) { 297 useParentHandlers = flag; 298 if (delegate != this) { 299 // merge in progress - propagate value to system peer. 300 final ConfigurationData system = delegate; 301 synchronized (system) { 302 system.useParentHandlers = useParentHandlers; 303 } 304 } 305 } 306 307 void setFilter(Filter f) { 308 filter = f; 309 if (delegate != this) { 310 // merge in progress - propagate value to system peer. 311 final ConfigurationData system = delegate; 312 synchronized (system) { 313 system.filter = filter; 314 } 315 } 316 } 317 318 void setLevelObject(Level l) { 319 levelObject = l; 320 if (delegate != this) { 321 // merge in progress - propagate value to system peer. 322 final ConfigurationData system = delegate; 323 synchronized (system) { 324 system.levelObject = levelObject; 325 } 326 } 327 } 328 329 void setLevelValue(int v) { 330 levelValue = v; 331 if (delegate != this) { 332 // merge in progress - propagate value to system peer. 333 final ConfigurationData system = delegate; 334 synchronized (system) { 335 system.levelValue = levelValue; 336 } 337 } 338 } 339 340 void addHandler(Handler h) { 341 if (handlers.add(h)) { 342 if (delegate != this) { 343 // merge in progress - propagate value to system peer. 344 final ConfigurationData system = delegate; 345 synchronized (system) { 346 system.handlers.addIfAbsent(h); 347 } 348 } 349 } 350 } 351 352 void removeHandler(Handler h) { 353 if (handlers.remove(h)) { 354 if (delegate != this) { 355 // merge in progress - propagate value to system peer. 356 final ConfigurationData system = delegate; 357 synchronized (system) { 358 system.handlers.remove(h); 359 } 360 } 361 } 362 } 363 364 ConfigurationData merge(Logger systemPeer) { 365 if (!systemPeer.isSystemLogger) { 366 // should never come here 367 throw new InternalError("not a system logger"); 368 } 369 370 ConfigurationData system = systemPeer.config; 371 372 if (system == this) { 373 // nothing to do 374 return system; 375 } 376 377 synchronized (system) { 378 // synchronize before checking on delegate to counter 379 // race conditions where two threads might attempt to 380 // merge concurrently 381 if (delegate == system) { 382 // merge already performed; 383 return system; 384 } 385 386 // publish system as the temporary delegate configuration. 387 // This should take care of potential race conditions where 388 // an other thread might attempt to call e.g. setlevel on 389 // the application logger while merge is in progress. 390 // (see implementation of ConfigurationData::setLevel) 391 delegate = system; 392 393 // merge this config object data into the system config 394 system.useParentHandlers = useParentHandlers; 395 system.filter = filter; 396 system.levelObject = levelObject; 397 system.levelValue = levelValue; 398 399 // Prevent race condition in case two threads attempt to merge 400 // configuration and add handlers at the same time. We don't want 401 // to add the same handlers twice. 402 // 403 // Handlers are created and loaded by LogManager.addLogger. If we 404 // reach here, then it means that the application logger has 405 // been created first and added with LogManager.addLogger, and the 406 // system logger was created after - and no handler has been added 407 // to it by LogManager.addLogger. Therefore, system.handlers 408 // should be empty. 409 // 410 // A non empty cfg.handlers list indicates a race condition 411 // where two threads might attempt to merge the configuration 412 // or add handlers concurrently. Though of no consequence for 413 // the other data (level etc...) this would be an issue if we 414 // added the same handlers twice. 415 // 416 for (Handler h : handlers) { 417 if (!system.handlers.contains(h)) { 418 systemPeer.addHandler(h); 419 } 420 } 421 system.handlers.retainAll(handlers); 422 system.handlers.addAllAbsent(handlers); 423 } 424 425 // sanity: update effective level after merging 426 synchronized(treeLock) { 427 systemPeer.updateEffectiveLevel(); 428 } 429 430 return system; 431 } 432 433 } 434 435 // The logger configuration data. Ideally, this should be final 436 // for system loggers, and replace-once for application loggers. 437 // When an application requests a logger by name, we do not know a-priori 438 // whether that corresponds to a system logger name or not. 439 // So if no system logger by that name already exists, we simply return an 440 // application logger. 441 // If a system class later requests a system logger of the same name, then 442 // the application logger and system logger configurations will be merged 443 // in a single instance of ConfigurationData that both loggers will share. 444 private volatile ConfigurationData config; 445 446 private volatile LogManager manager; 447 private String name; 448 private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE; 449 private boolean anonymous; 450 451 // Cache to speed up behavior of findResourceBundle: 452 private ResourceBundle catalog; // Cached resource bundle 453 private String catalogName; // name associated with catalog 454 private Locale catalogLocale; // locale associated with catalog 455 456 // The fields relating to parent-child relationships and levels 457 // are managed under a separate lock, the treeLock. 458 private static final Object treeLock = new Object(); 459 // We keep weak references from parents to children, but strong 460 // references from children to parents. 461 private volatile Logger parent; // our nearest parent. 462 private ArrayList<LogManager.LoggerWeakRef> kids; // WeakReferences to loggers that have us as parent 463 private WeakReference<Module> callerModuleRef; 464 private final boolean isSystemLogger; 465 466 /** 467 * GLOBAL_LOGGER_NAME is a name for the global logger. 468 * 469 * @since 1.6 470 */ 471 public static final String GLOBAL_LOGGER_NAME = "global"; 472 473 /** 474 * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME. 475 * 476 * @return global logger object 477 * @since 1.7 478 */ 479 public static final Logger getGlobal() { 480 // In order to break a cyclic dependence between the LogManager 481 // and Logger static initializers causing deadlocks, the global 482 // logger is created with a special constructor that does not 483 // initialize its log manager. 484 // 485 // If an application calls Logger.getGlobal() before any logger 486 // has been initialized, it is therefore possible that the 487 // LogManager class has not been initialized yet, and therefore 488 // Logger.global.manager will be null. 489 // 490 // In order to finish the initialization of the global logger, we 491 // will therefore call LogManager.getLogManager() here. 492 // 493 // To prevent race conditions we also need to call 494 // LogManager.getLogManager() unconditionally here. 495 // Indeed we cannot rely on the observed value of global.manager, 496 // because global.manager will become not null somewhere during 497 // the initialization of LogManager. 498 // If two threads are calling getGlobal() concurrently, one thread 499 // will see global.manager null and call LogManager.getLogManager(), 500 // but the other thread could come in at a time when global.manager 501 // is already set although ensureLogManagerInitialized is not finished 502 // yet... 503 // Calling LogManager.getLogManager() unconditionally will fix that. 504 505 LogManager.getLogManager(); 506 507 // Now the global LogManager should be initialized, 508 // and the global logger should have been added to 509 // it, unless we were called within the constructor of a LogManager 510 // subclass installed as LogManager, in which case global.manager 511 // would still be null, and global will be lazily initialized later on. 512 513 return global; 514 } 515 516 /** 517 * The "global" Logger object is provided as a convenience to developers 518 * who are making casual use of the Logging package. Developers 519 * who are making serious use of the logging package (for example 520 * in products) should create and use their own Logger objects, 521 * with appropriate names, so that logging can be controlled on a 522 * suitable per-Logger granularity. Developers also need to keep a 523 * strong reference to their Logger objects to prevent them from 524 * being garbage collected. 525 * 526 * @deprecated Initialization of this field is prone to deadlocks. 527 * The field must be initialized by the Logger class initialization 528 * which may cause deadlocks with the LogManager class initialization. 529 * In such cases two class initialization wait for each other to complete. 530 * The preferred way to get the global logger object is via the call 531 * {@code Logger.getGlobal()}. 532 * For compatibility with old JDK versions where the 533 * {@code Logger.getGlobal()} is not available use the call 534 * {@code Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)} 535 * or {@code Logger.getLogger("global")}. 536 */ 537 @Deprecated 538 public static final Logger global = new Logger(GLOBAL_LOGGER_NAME); 539 540 /** 541 * Protected method to construct a logger for a named subsystem. 542 * <p> 543 * The logger will be initially configured with a null Level 544 * and with useParentHandlers set to true. 545 * 546 * @param name A name for the logger. This should 547 * be a dot-separated name and should normally 548 * be based on the package name or class name 549 * of the subsystem, such as java.net 550 * or javax.swing. It may be null for anonymous Loggers. 551 * @param resourceBundleName name of ResourceBundle to be used for localizing 552 * messages for this logger. May be null if none 553 * of the messages require localization. 554 * @throws MissingResourceException if the resourceBundleName is non-null and 555 * no corresponding resource can be found. 556 */ 557 protected Logger(String name, String resourceBundleName) { 558 this(name, resourceBundleName, null, LogManager.getLogManager(), false); 559 } 560 561 Logger(String name, String resourceBundleName, Module caller, 562 LogManager manager, boolean isSystemLogger) { 563 this.manager = manager; 564 this.isSystemLogger = isSystemLogger; 565 this.config = new ConfigurationData(); 566 this.name = name; 567 setupResourceInfo(resourceBundleName, caller); 568 } 569 570 // Called by LogManager when a system logger is created 571 // after a user logger of the same name. 572 // Ensure that both loggers will share the same 573 // configuration. 574 final void mergeWithSystemLogger(Logger system) { 575 // sanity checks 576 if (!system.isSystemLogger 577 || anonymous 578 || name == null 579 || !name.equals(system.name)) { 580 // should never come here 581 throw new InternalError("invalid logger merge"); 582 } 583 checkPermission(); 584 final ConfigurationData cfg = config; 585 if (cfg != system.config) { 586 config = cfg.merge(system); 587 } 588 } 589 590 private void setCallerModuleRef(Module callerModule) { 591 if (callerModule != null) { 592 this.callerModuleRef = new WeakReference<>(callerModule); 593 } 594 } 595 596 private Module getCallerModule() { 597 return (callerModuleRef != null) 598 ? callerModuleRef.get() 599 : null; 600 } 601 602 // This constructor is used only to create the global Logger. 603 // It is needed to break a cyclic dependence between the LogManager 604 // and Logger static initializers causing deadlocks. 605 private Logger(String name) { 606 // The manager field is not initialized here. 607 this.name = name; 608 this.isSystemLogger = true; 609 config = new ConfigurationData(); 610 } 611 612 // It is called from LoggerContext.addLocalLogger() when the logger 613 // is actually added to a LogManager. 614 void setLogManager(LogManager manager) { 615 this.manager = manager; 616 } 617 618 private void checkPermission() throws SecurityException { 619 if (!anonymous) { 620 if (manager == null) { 621 // Complete initialization of the global Logger. 622 manager = LogManager.getLogManager(); 623 } 624 manager.checkPermission(); 625 } 626 } 627 628 // Until all JDK code converted to call sun.util.logging.PlatformLogger 629 // (see 7054233), we need to determine if Logger.getLogger is to add 630 // a system logger or user logger. 631 // 632 // As an interim solution, if the immediate caller whose caller loader is 633 // null, we assume it's a system logger and add it to the system context. 634 // These system loggers only set the resource bundle to the given 635 // resource bundle name (rather than the default system resource bundle). 636 private static class SystemLoggerHelper { 637 static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); 638 private static boolean getBooleanProperty(final String key) { 639 String s = AccessController.doPrivileged(new PrivilegedAction<String>() { 640 @Override 641 public String run() { 642 return System.getProperty(key); 643 } 644 }); 645 return Boolean.valueOf(s); 646 } 647 } 648 649 private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 650 LogManager manager = LogManager.getLogManager(); 651 if (!SystemLoggerHelper.disableCallerCheck) { 652 if (isSystem(caller.getModule())) { 653 return manager.demandSystemLogger(name, resourceBundleName, caller); 654 } 655 } 656 return manager.demandLogger(name, resourceBundleName, caller); 657 // ends up calling new Logger(name, resourceBundleName, caller) 658 // iff the logger doesn't exist already 659 } 660 661 /** 662 * Find or create a logger for a named subsystem. If a logger has 663 * already been created with the given name it is returned. Otherwise 664 * a new logger is created. 665 * <p> 666 * If a new logger is created its log level will be configured 667 * based on the LogManager configuration and it will configured 668 * to also send logging output to its parent's Handlers. It will 669 * be registered in the LogManager global namespace. 670 * <p> 671 * Note: The LogManager may only retain a weak reference to the newly 672 * created Logger. It is important to understand that a previously 673 * created Logger with the given name may be garbage collected at any 674 * time if there is no strong reference to the Logger. In particular, 675 * this means that two back-to-back calls like 676 * {@code getLogger("MyLogger").log(...)} may use different Logger 677 * objects named "MyLogger" if there is no strong reference to the 678 * Logger named "MyLogger" elsewhere in the program. 679 * 680 * @param name A name for the logger. This should 681 * be a dot-separated name and should normally 682 * be based on the package name or class name 683 * of the subsystem, such as java.net 684 * or javax.swing 685 * @return a suitable Logger 686 * @throws NullPointerException if the name is null. 687 */ 688 689 // Synchronization is not required here. All synchronization for 690 // adding a new Logger object is handled by LogManager.addLogger(). 691 @CallerSensitive 692 public static Logger getLogger(String name) { 693 // This method is intentionally not a wrapper around a call 694 // to getLogger(name, resourceBundleName). If it were then 695 // this sequence: 696 // 697 // getLogger("Foo", "resourceBundleForFoo"); 698 // getLogger("Foo"); 699 // 700 // would throw an IllegalArgumentException in the second call 701 // because the wrapper would result in an attempt to replace 702 // the existing "resourceBundleForFoo" with null. 703 return Logger.getLogger(name, Reflection.getCallerClass()); 704 } 705 706 /** 707 * Find or create a logger for a named subsystem on behalf 708 * of the given caller. 709 * 710 * This method is called by {@link #getLogger(java.lang.String)} after 711 * it has obtained a reference to its caller's class. 712 * 713 * @param name A name for the logger. 714 * @param callerClass The class that called {@link 715 * #getLogger(java.lang.String)}. 716 * @return a suitable Logger for {@code callerClass}. 717 */ 718 private static Logger getLogger(String name, Class<?> callerClass) { 719 return demandLogger(name, null, callerClass); 720 } 721 722 /** 723 * Find or create a logger for a named subsystem. If a logger has 724 * already been created with the given name it is returned. Otherwise 725 * a new logger is created. 726 * 727 * <p> 728 * If a new logger is created its log level will be configured 729 * based on the LogManager and it will configured to also send logging 730 * output to its parent's Handlers. It will be registered in 731 * the LogManager global namespace. 732 * <p> 733 * Note: The LogManager may only retain a weak reference to the newly 734 * created Logger. It is important to understand that a previously 735 * created Logger with the given name may be garbage collected at any 736 * time if there is no strong reference to the Logger. In particular, 737 * this means that two back-to-back calls like 738 * {@code getLogger("MyLogger", ...).log(...)} may use different Logger 739 * objects named "MyLogger" if there is no strong reference to the 740 * Logger named "MyLogger" elsewhere in the program. 741 * <p> 742 * If the named Logger already exists and does not yet have a 743 * localization resource bundle then the given resource bundle 744 * name is used. If the named Logger already exists and has 745 * a different resource bundle name then an IllegalArgumentException 746 * is thrown. 747 * 748 * @param name A name for the logger. This should 749 * be a dot-separated name and should normally 750 * be based on the package name or class name 751 * of the subsystem, such as java.net 752 * or javax.swing 753 * @param resourceBundleName name of ResourceBundle to be used for localizing 754 * messages for this logger. May be {@code null} 755 * if none of the messages require localization. 756 * @return a suitable Logger 757 * @throws MissingResourceException if the resourceBundleName is non-null and 758 * no corresponding resource can be found. 759 * @throws IllegalArgumentException if the Logger already exists and uses 760 * a different resource bundle name; or if 761 * {@code resourceBundleName} is {@code null} but the named 762 * logger has a resource bundle set. 763 * @throws NullPointerException if the name is null. 764 */ 765 766 // Synchronization is not required here. All synchronization for 767 // adding a new Logger object is handled by LogManager.addLogger(). 768 @CallerSensitive 769 public static Logger getLogger(String name, String resourceBundleName) { 770 return Logger.getLogger(name, resourceBundleName, Reflection.getCallerClass()); 771 } 772 773 /** 774 * Find or create a logger for a named subsystem on behalf 775 * of the given caller. 776 * 777 * This method is called by {@link 778 * #getLogger(java.lang.String, java.lang.String)} after 779 * it has obtained a reference to its caller's class. 780 * 781 * @param name A name for the logger. 782 * @param resourceBundleName name of ResourceBundle to be used for localizing 783 * messages for this logger. May be {@code null} 784 * if none of the messages require localization. 785 * @param callerClass The class that called {@link 786 * #getLogger(java.lang.String, java.lang.String)}. 787 * This class will also be used for locating the 788 * resource bundle if {@code resourceBundleName} is 789 * not {@code null}. 790 * @return a suitable Logger for {@code callerClass}. 791 */ 792 private static Logger getLogger(String name, String resourceBundleName, 793 Class<?> callerClass) { 794 Logger result = demandLogger(name, resourceBundleName, callerClass); 795 796 // MissingResourceException or IllegalArgumentException can be 797 // thrown by setupResourceInfo(). 798 // We have to set the callers ClassLoader here in case demandLogger 799 // above found a previously created Logger. This can happen, for 800 // example, if Logger.getLogger(name) is called and subsequently 801 // Logger.getLogger(name, resourceBundleName) is called. In this case 802 // we won't necessarily have the correct classloader saved away, so 803 // we need to set it here, too. 804 805 result.setupResourceInfo(resourceBundleName, callerClass); 806 return result; 807 } 808 809 // package-private 810 // Add a platform logger to the system context. 811 // i.e. caller of sun.util.logging.PlatformLogger.getLogger 812 static Logger getPlatformLogger(String name) { 813 LogManager manager = LogManager.getLogManager(); 814 815 // all loggers in the system context will default to 816 // the system logger's resource bundle - therefore the caller won't 817 // be needed and can be null. 818 Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, (Module)null); 819 return result; 820 } 821 822 /** 823 * Create an anonymous Logger. The newly created Logger is not 824 * registered in the LogManager namespace. There will be no 825 * access checks on updates to the logger. 826 * <p> 827 * This factory method is primarily intended for use from applets. 828 * Because the resulting Logger is anonymous it can be kept private 829 * by the creating class. This removes the need for normal security 830 * checks, which in turn allows untrusted applet code to update 831 * the control state of the Logger. For example an applet can do 832 * a setLevel or an addHandler on an anonymous Logger. 833 * <p> 834 * Even although the new logger is anonymous, it is configured 835 * to have the root logger ("") as its parent. This means that 836 * by default it inherits its effective level and handlers 837 * from the root logger. Changing its parent via the 838 * {@link #setParent(java.util.logging.Logger) setParent} method 839 * will still require the security permission specified by that method. 840 * 841 * @return a newly created private Logger 842 */ 843 public static Logger getAnonymousLogger() { 844 return getAnonymousLogger(null); 845 } 846 847 /** 848 * Create an anonymous Logger. The newly created Logger is not 849 * registered in the LogManager namespace. There will be no 850 * access checks on updates to the logger. 851 * <p> 852 * This factory method is primarily intended for use from applets. 853 * Because the resulting Logger is anonymous it can be kept private 854 * by the creating class. This removes the need for normal security 855 * checks, which in turn allows untrusted applet code to update 856 * the control state of the Logger. For example an applet can do 857 * a setLevel or an addHandler on an anonymous Logger. 858 * <p> 859 * Even although the new logger is anonymous, it is configured 860 * to have the root logger ("") as its parent. This means that 861 * by default it inherits its effective level and handlers 862 * from the root logger. Changing its parent via the 863 * {@link #setParent(java.util.logging.Logger) setParent} method 864 * will still require the security permission specified by that method. 865 * 866 * @param resourceBundleName name of ResourceBundle to be used for localizing 867 * messages for this logger. 868 * May be null if none of the messages require localization. 869 * @return a newly created private Logger 870 * @throws MissingResourceException if the resourceBundleName is non-null and 871 * no corresponding resource can be found. 872 */ 873 874 // Synchronization is not required here. All synchronization for 875 // adding a new anonymous Logger object is handled by doSetParent(). 876 @CallerSensitive 877 public static Logger getAnonymousLogger(String resourceBundleName) { 878 LogManager manager = LogManager.getLogManager(); 879 // cleanup some Loggers that have been GC'ed 880 manager.drainLoggerRefQueueBounded(); 881 final Class<?> callerClass = Reflection.getCallerClass(); 882 final Module module = callerClass.getModule(); 883 Logger result = new Logger(null, resourceBundleName, 884 module, manager, false); 885 result.anonymous = true; 886 Logger root = manager.getLogger(""); 887 result.doSetParent(root); 888 return result; 889 } 890 891 /** 892 * Retrieve the localization resource bundle for this 893 * logger. 894 * This method will return a {@code ResourceBundle} that was either 895 * set by the {@link 896 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or 897 * <a href="#ResourceBundleMapping">mapped from the 898 * the resource bundle name</a> set via the {@link 899 * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory 900 * method for the current default locale. 901 * <br>Note that if the result is {@code null}, then the Logger will use a resource 902 * bundle or resource bundle name inherited from its parent. 903 * 904 * @return localization bundle (may be {@code null}) 905 */ 906 public ResourceBundle getResourceBundle() { 907 return findResourceBundle(getResourceBundleName(), true); 908 } 909 910 /** 911 * Retrieve the localization resource bundle name for this 912 * logger. 913 * This is either the name specified through the {@link 914 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method, 915 * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the 916 * ResourceBundle set through {@link 917 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 918 * <br>Note that if the result is {@code null}, then the Logger will use a resource 919 * bundle or resource bundle name inherited from its parent. 920 * 921 * @return localization bundle name (may be {@code null}) 922 */ 923 public String getResourceBundleName() { 924 return loggerBundle.resourceBundleName; 925 } 926 927 /** 928 * Set a filter to control output on this Logger. 929 * <P> 930 * After passing the initial "level" check, the Logger will 931 * call this Filter to check if a log record should really 932 * be published. 933 * 934 * @param newFilter a filter object (may be null) 935 * @throws SecurityException if a security manager exists, 936 * this logger is not anonymous, and the caller 937 * does not have LoggingPermission("control"). 938 */ 939 public void setFilter(Filter newFilter) throws SecurityException { 940 checkPermission(); 941 config.setFilter(newFilter); 942 } 943 944 /** 945 * Get the current filter for this Logger. 946 * 947 * @return a filter object (may be null) 948 */ 949 public Filter getFilter() { 950 return config.filter; 951 } 952 953 /** 954 * Log a LogRecord. 955 * <p> 956 * All the other logging methods in this class call through 957 * this method to actually perform any logging. Subclasses can 958 * override this single method to capture all log activity. 959 * 960 * @param record the LogRecord to be published 961 */ 962 public void log(LogRecord record) { 963 if (!isLoggable(record.getLevel())) { 964 return; 965 } 966 Filter theFilter = config.filter; 967 if (theFilter != null && !theFilter.isLoggable(record)) { 968 return; 969 } 970 971 // Post the LogRecord to all our Handlers, and then to 972 // our parents' handlers, all the way up the tree. 973 974 Logger logger = this; 975 while (logger != null) { 976 final Handler[] loggerHandlers = isSystemLogger 977 ? logger.accessCheckedHandlers() 978 : logger.getHandlers(); 979 980 for (Handler handler : loggerHandlers) { 981 handler.publish(record); 982 } 983 984 final boolean useParentHdls = isSystemLogger 985 ? logger.config.useParentHandlers 986 : logger.getUseParentHandlers(); 987 988 if (!useParentHdls) { 989 break; 990 } 991 992 logger = isSystemLogger ? logger.parent : logger.getParent(); 993 } 994 } 995 996 // private support method for logging. 997 // We fill in the logger name, resource bundle name, and 998 // resource bundle and then call "void log(LogRecord)". 999 private void doLog(LogRecord lr) { 1000 lr.setLoggerName(name); 1001 final LoggerBundle lb = getEffectiveLoggerBundle(); 1002 final ResourceBundle bundle = lb.userBundle; 1003 final String ebname = lb.resourceBundleName; 1004 if (ebname != null && bundle != null) { 1005 lr.setResourceBundleName(ebname); 1006 lr.setResourceBundle(bundle); 1007 } 1008 log(lr); 1009 } 1010 1011 1012 //================================================================ 1013 // Start of convenience methods WITHOUT className and methodName 1014 //================================================================ 1015 1016 /** 1017 * Log a message, with no arguments. 1018 * <p> 1019 * If the logger is currently enabled for the given message 1020 * level then the given message is forwarded to all the 1021 * registered output Handler objects. 1022 * 1023 * @param level One of the message level identifiers, e.g., SEVERE 1024 * @param msg The string message (or a key in the message catalog) 1025 */ 1026 public void log(Level level, String msg) { 1027 if (!isLoggable(level)) { 1028 return; 1029 } 1030 LogRecord lr = new LogRecord(level, msg); 1031 doLog(lr); 1032 } 1033 1034 /** 1035 * Log a message, which is only to be constructed if the logging level 1036 * is such that the message will actually be logged. 1037 * <p> 1038 * If the logger is currently enabled for the given message 1039 * level then the message is constructed by invoking the provided 1040 * supplier function and forwarded to all the registered output 1041 * Handler objects. 1042 * 1043 * @param level One of the message level identifiers, e.g., SEVERE 1044 * @param msgSupplier A function, which when called, produces the 1045 * desired log message 1046 * @since 1.8 1047 */ 1048 public void log(Level level, Supplier<String> msgSupplier) { 1049 if (!isLoggable(level)) { 1050 return; 1051 } 1052 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1053 doLog(lr); 1054 } 1055 1056 /** 1057 * Log a message, with one object parameter. 1058 * <p> 1059 * If the logger is currently enabled for the given message 1060 * level then a corresponding LogRecord is created and forwarded 1061 * to all the registered output Handler objects. 1062 * 1063 * @param level One of the message level identifiers, e.g., SEVERE 1064 * @param msg The string message (or a key in the message catalog) 1065 * @param param1 parameter to the message 1066 */ 1067 public void log(Level level, String msg, Object param1) { 1068 if (!isLoggable(level)) { 1069 return; 1070 } 1071 LogRecord lr = new LogRecord(level, msg); 1072 Object params[] = { param1 }; 1073 lr.setParameters(params); 1074 doLog(lr); 1075 } 1076 1077 /** 1078 * Log a message, with an array of object arguments. 1079 * <p> 1080 * If the logger is currently enabled for the given message 1081 * level then a corresponding LogRecord is created and forwarded 1082 * to all the registered output Handler objects. 1083 * 1084 * @param level One of the message level identifiers, e.g., SEVERE 1085 * @param msg The string message (or a key in the message catalog) 1086 * @param params array of parameters to the message 1087 */ 1088 public void log(Level level, String msg, Object params[]) { 1089 if (!isLoggable(level)) { 1090 return; 1091 } 1092 LogRecord lr = new LogRecord(level, msg); 1093 lr.setParameters(params); 1094 doLog(lr); 1095 } 1096 1097 /** 1098 * Log a message, with associated Throwable information. 1099 * <p> 1100 * If the logger is currently enabled for the given message 1101 * level then the given arguments are stored in a LogRecord 1102 * which is forwarded to all registered output handlers. 1103 * <p> 1104 * Note that the thrown argument is stored in the LogRecord thrown 1105 * property, rather than the LogRecord parameters property. Thus it is 1106 * processed specially by output Formatters and is not treated 1107 * as a formatting parameter to the LogRecord message property. 1108 * 1109 * @param level One of the message level identifiers, e.g., SEVERE 1110 * @param msg The string message (or a key in the message catalog) 1111 * @param thrown Throwable associated with log message. 1112 */ 1113 public void log(Level level, String msg, Throwable thrown) { 1114 if (!isLoggable(level)) { 1115 return; 1116 } 1117 LogRecord lr = new LogRecord(level, msg); 1118 lr.setThrown(thrown); 1119 doLog(lr); 1120 } 1121 1122 /** 1123 * Log a lazily constructed message, with associated Throwable information. 1124 * <p> 1125 * If the logger is currently enabled for the given message level then the 1126 * message is constructed by invoking the provided supplier function. The 1127 * message and the given {@link Throwable} are then stored in a {@link 1128 * LogRecord} which is forwarded to all registered output handlers. 1129 * <p> 1130 * Note that the thrown argument is stored in the LogRecord thrown 1131 * property, rather than the LogRecord parameters property. Thus it is 1132 * processed specially by output Formatters and is not treated 1133 * as a formatting parameter to the LogRecord message property. 1134 * 1135 * @param level One of the message level identifiers, e.g., SEVERE 1136 * @param thrown Throwable associated with log message. 1137 * @param msgSupplier A function, which when called, produces the 1138 * desired log message 1139 * @since 1.8 1140 */ 1141 public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) { 1142 if (!isLoggable(level)) { 1143 return; 1144 } 1145 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1146 lr.setThrown(thrown); 1147 doLog(lr); 1148 } 1149 1150 //================================================================ 1151 // Start of convenience methods WITH className and methodName 1152 //================================================================ 1153 1154 /** 1155 * Log a message, specifying source class and method, 1156 * with no arguments. 1157 * <p> 1158 * If the logger is currently enabled for the given message 1159 * level then the given message is forwarded to all the 1160 * registered output Handler objects. 1161 * 1162 * @param level One of the message level identifiers, e.g., SEVERE 1163 * @param sourceClass name of class that issued the logging request 1164 * @param sourceMethod name of method that issued the logging request 1165 * @param msg The string message (or a key in the message catalog) 1166 */ 1167 public void logp(Level level, String sourceClass, String sourceMethod, String msg) { 1168 if (!isLoggable(level)) { 1169 return; 1170 } 1171 LogRecord lr = new LogRecord(level, msg); 1172 lr.setSourceClassName(sourceClass); 1173 lr.setSourceMethodName(sourceMethod); 1174 doLog(lr); 1175 } 1176 1177 /** 1178 * Log a lazily constructed message, specifying source class and method, 1179 * with no arguments. 1180 * <p> 1181 * If the logger is currently enabled for the given message 1182 * level then the message is constructed by invoking the provided 1183 * supplier function and forwarded to all the registered output 1184 * Handler objects. 1185 * 1186 * @param level One of the message level identifiers, e.g., SEVERE 1187 * @param sourceClass name of class that issued the logging request 1188 * @param sourceMethod name of method that issued the logging request 1189 * @param msgSupplier A function, which when called, produces the 1190 * desired log message 1191 * @since 1.8 1192 */ 1193 public void logp(Level level, String sourceClass, String sourceMethod, 1194 Supplier<String> msgSupplier) { 1195 if (!isLoggable(level)) { 1196 return; 1197 } 1198 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1199 lr.setSourceClassName(sourceClass); 1200 lr.setSourceMethodName(sourceMethod); 1201 doLog(lr); 1202 } 1203 1204 /** 1205 * Log a message, specifying source class and method, 1206 * with a single object parameter to the log message. 1207 * <p> 1208 * If the logger is currently enabled for the given message 1209 * level then a corresponding LogRecord is created and forwarded 1210 * to all the registered output Handler objects. 1211 * 1212 * @param level One of the message level identifiers, e.g., SEVERE 1213 * @param sourceClass name of class that issued the logging request 1214 * @param sourceMethod name of method that issued the logging request 1215 * @param msg The string message (or a key in the message catalog) 1216 * @param param1 Parameter to the log message. 1217 */ 1218 public void logp(Level level, String sourceClass, String sourceMethod, 1219 String msg, Object param1) { 1220 if (!isLoggable(level)) { 1221 return; 1222 } 1223 LogRecord lr = new LogRecord(level, msg); 1224 lr.setSourceClassName(sourceClass); 1225 lr.setSourceMethodName(sourceMethod); 1226 Object params[] = { param1 }; 1227 lr.setParameters(params); 1228 doLog(lr); 1229 } 1230 1231 /** 1232 * Log a message, specifying source class and method, 1233 * with an array of object arguments. 1234 * <p> 1235 * If the logger is currently enabled for the given message 1236 * level then a corresponding LogRecord is created and forwarded 1237 * to all the registered output Handler objects. 1238 * 1239 * @param level One of the message level identifiers, e.g., SEVERE 1240 * @param sourceClass name of class that issued the logging request 1241 * @param sourceMethod name of method that issued the logging request 1242 * @param msg The string message (or a key in the message catalog) 1243 * @param params Array of parameters to the message 1244 */ 1245 public void logp(Level level, String sourceClass, String sourceMethod, 1246 String msg, Object params[]) { 1247 if (!isLoggable(level)) { 1248 return; 1249 } 1250 LogRecord lr = new LogRecord(level, msg); 1251 lr.setSourceClassName(sourceClass); 1252 lr.setSourceMethodName(sourceMethod); 1253 lr.setParameters(params); 1254 doLog(lr); 1255 } 1256 1257 /** 1258 * Log a message, specifying source class and method, 1259 * with associated Throwable information. 1260 * <p> 1261 * If the logger is currently enabled for the given message 1262 * level then the given arguments are stored in a LogRecord 1263 * which is forwarded to all registered output handlers. 1264 * <p> 1265 * Note that the thrown argument is stored in the LogRecord thrown 1266 * property, rather than the LogRecord parameters property. Thus it is 1267 * processed specially by output Formatters and is not treated 1268 * as a formatting parameter to the LogRecord message property. 1269 * 1270 * @param level One of the message level identifiers, e.g., SEVERE 1271 * @param sourceClass name of class that issued the logging request 1272 * @param sourceMethod name of method that issued the logging request 1273 * @param msg The string message (or a key in the message catalog) 1274 * @param thrown Throwable associated with log message. 1275 */ 1276 public void logp(Level level, String sourceClass, String sourceMethod, 1277 String msg, Throwable thrown) { 1278 if (!isLoggable(level)) { 1279 return; 1280 } 1281 LogRecord lr = new LogRecord(level, msg); 1282 lr.setSourceClassName(sourceClass); 1283 lr.setSourceMethodName(sourceMethod); 1284 lr.setThrown(thrown); 1285 doLog(lr); 1286 } 1287 1288 /** 1289 * Log a lazily constructed message, specifying source class and method, 1290 * with associated Throwable information. 1291 * <p> 1292 * If the logger is currently enabled for the given message level then the 1293 * message is constructed by invoking the provided supplier function. The 1294 * message and the given {@link Throwable} are then stored in a {@link 1295 * LogRecord} which is forwarded to all registered output handlers. 1296 * <p> 1297 * Note that the thrown argument is stored in the LogRecord thrown 1298 * property, rather than the LogRecord parameters property. Thus it is 1299 * processed specially by output Formatters and is not treated 1300 * as a formatting parameter to the LogRecord message property. 1301 * 1302 * @param level One of the message level identifiers, e.g., SEVERE 1303 * @param sourceClass name of class that issued the logging request 1304 * @param sourceMethod name of method that issued the logging request 1305 * @param thrown Throwable associated with log message. 1306 * @param msgSupplier A function, which when called, produces the 1307 * desired log message 1308 * @since 1.8 1309 */ 1310 public void logp(Level level, String sourceClass, String sourceMethod, 1311 Throwable thrown, Supplier<String> msgSupplier) { 1312 if (!isLoggable(level)) { 1313 return; 1314 } 1315 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1316 lr.setSourceClassName(sourceClass); 1317 lr.setSourceMethodName(sourceMethod); 1318 lr.setThrown(thrown); 1319 doLog(lr); 1320 } 1321 1322 1323 //========================================================================= 1324 // Start of convenience methods WITH className, methodName and bundle name. 1325 //========================================================================= 1326 1327 // Private support method for logging for "logrb" methods. 1328 // We fill in the logger name, resource bundle name, and 1329 // resource bundle and then call "void log(LogRecord)". 1330 private void doLog(LogRecord lr, String rbname) { 1331 lr.setLoggerName(name); 1332 if (rbname != null) { 1333 lr.setResourceBundleName(rbname); 1334 lr.setResourceBundle(findResourceBundle(rbname, false)); 1335 } 1336 log(lr); 1337 } 1338 1339 // Private support method for logging for "logrb" methods. 1340 private void doLog(LogRecord lr, ResourceBundle rb) { 1341 lr.setLoggerName(name); 1342 if (rb != null) { 1343 lr.setResourceBundleName(rb.getBaseBundleName()); 1344 lr.setResourceBundle(rb); 1345 } 1346 log(lr); 1347 } 1348 1349 /** 1350 * Log a message, specifying source class, method, and resource bundle name 1351 * with no arguments. 1352 * <p> 1353 * If the logger is currently enabled for the given message 1354 * level then the given message is forwarded to all the 1355 * registered output Handler objects. 1356 * <p> 1357 * The msg string is localized using the named resource bundle. If the 1358 * resource bundle name is null, or an empty String or invalid 1359 * then the msg string is not localized. 1360 * 1361 * @param level One of the message level identifiers, e.g., SEVERE 1362 * @param sourceClass name of class that issued the logging request 1363 * @param sourceMethod name of method that issued the logging request 1364 * @param bundleName name of resource bundle to localize msg, 1365 * can be null 1366 * @param msg The string message (or a key in the message catalog) 1367 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1368 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1369 * java.lang.Object...)} instead. 1370 */ 1371 @Deprecated 1372 public void logrb(Level level, String sourceClass, String sourceMethod, 1373 String bundleName, String msg) { 1374 if (!isLoggable(level)) { 1375 return; 1376 } 1377 LogRecord lr = new LogRecord(level, msg); 1378 lr.setSourceClassName(sourceClass); 1379 lr.setSourceMethodName(sourceMethod); 1380 doLog(lr, bundleName); 1381 } 1382 1383 /** 1384 * Log a message, specifying source class, method, and resource bundle name, 1385 * with a single object parameter to the log message. 1386 * <p> 1387 * If the logger is currently enabled for the given message 1388 * level then a corresponding LogRecord is created and forwarded 1389 * to all the registered output Handler objects. 1390 * <p> 1391 * The msg string is localized using the named resource bundle. If the 1392 * resource bundle name is null, or an empty String or invalid 1393 * then the msg string is not localized. 1394 * 1395 * @param level One of the message level identifiers, e.g., SEVERE 1396 * @param sourceClass name of class that issued the logging request 1397 * @param sourceMethod name of method that issued the logging request 1398 * @param bundleName name of resource bundle to localize msg, 1399 * can be null 1400 * @param msg The string message (or a key in the message catalog) 1401 * @param param1 Parameter to the log message. 1402 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1403 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1404 * java.lang.Object...)} instead 1405 */ 1406 @Deprecated 1407 public void logrb(Level level, String sourceClass, String sourceMethod, 1408 String bundleName, String msg, Object param1) { 1409 if (!isLoggable(level)) { 1410 return; 1411 } 1412 LogRecord lr = new LogRecord(level, msg); 1413 lr.setSourceClassName(sourceClass); 1414 lr.setSourceMethodName(sourceMethod); 1415 Object params[] = { param1 }; 1416 lr.setParameters(params); 1417 doLog(lr, bundleName); 1418 } 1419 1420 /** 1421 * Log a message, specifying source class, method, and resource bundle name, 1422 * with an array of object arguments. 1423 * <p> 1424 * If the logger is currently enabled for the given message 1425 * level then a corresponding LogRecord is created and forwarded 1426 * to all the registered output Handler objects. 1427 * <p> 1428 * The msg string is localized using the named resource bundle. If the 1429 * resource bundle name is null, or an empty String or invalid 1430 * then the msg string is not localized. 1431 * 1432 * @param level One of the message level identifiers, e.g., SEVERE 1433 * @param sourceClass name of class that issued the logging request 1434 * @param sourceMethod name of method that issued the logging request 1435 * @param bundleName name of resource bundle to localize msg, 1436 * can be null. 1437 * @param msg The string message (or a key in the message catalog) 1438 * @param params Array of parameters to the message 1439 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1440 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1441 * java.lang.Object...)} instead. 1442 */ 1443 @Deprecated 1444 public void logrb(Level level, String sourceClass, String sourceMethod, 1445 String bundleName, String msg, Object params[]) { 1446 if (!isLoggable(level)) { 1447 return; 1448 } 1449 LogRecord lr = new LogRecord(level, msg); 1450 lr.setSourceClassName(sourceClass); 1451 lr.setSourceMethodName(sourceMethod); 1452 lr.setParameters(params); 1453 doLog(lr, bundleName); 1454 } 1455 1456 /** 1457 * Log a message, specifying source class, method, and resource bundle, 1458 * with an optional list of message parameters. 1459 * <p> 1460 * If the logger is currently enabled for the given message 1461 * {@code level} then a corresponding {@code LogRecord} is created and 1462 * forwarded to all the registered output {@code Handler} objects. 1463 * <p> 1464 * The {@code msg} string is localized using the given resource bundle. 1465 * If the resource bundle is {@code null}, then the {@code msg} string is not 1466 * localized. 1467 * 1468 * @param level One of the message level identifiers, e.g., {@code SEVERE} 1469 * @param sourceClass Name of the class that issued the logging request 1470 * @param sourceMethod Name of the method that issued the logging request 1471 * @param bundle Resource bundle to localize {@code msg}, 1472 * can be {@code null}. 1473 * @param msg The string message (or a key in the message catalog) 1474 * @param params Parameters to the message (optional, may be none). 1475 * @since 1.8 1476 */ 1477 public void logrb(Level level, String sourceClass, String sourceMethod, 1478 ResourceBundle bundle, String msg, Object... params) { 1479 if (!isLoggable(level)) { 1480 return; 1481 } 1482 LogRecord lr = new LogRecord(level, msg); 1483 lr.setSourceClassName(sourceClass); 1484 lr.setSourceMethodName(sourceMethod); 1485 if (params != null && params.length != 0) { 1486 lr.setParameters(params); 1487 } 1488 doLog(lr, bundle); 1489 } 1490 1491 /** 1492 * Log a message, specifying source class, method, and resource bundle, 1493 * with an optional list of message parameters. 1494 * <p> 1495 * If the logger is currently enabled for the given message 1496 * {@code level} then a corresponding {@code LogRecord} is created 1497 * and forwarded to all the registered output {@code Handler} objects. 1498 * <p> 1499 * The {@code msg} string is localized using the given resource bundle. 1500 * If the resource bundle is {@code null}, then the {@code msg} string is not 1501 * localized. 1502 * <p> 1503 * @param level One of the message level identifiers, e.g., {@code SEVERE} 1504 * @param bundle Resource bundle to localize {@code msg}; 1505 * can be {@code null}. 1506 * @param msg The string message (or a key in the message catalog) 1507 * @param params Parameters to the message (optional, may be none). 1508 * @since 9 1509 */ 1510 public void logrb(Level level, ResourceBundle bundle, String msg, Object... params) { 1511 if (!isLoggable(level)) { 1512 return; 1513 } 1514 LogRecord lr = new LogRecord(level, msg); 1515 if (params != null && params.length != 0) { 1516 lr.setParameters(params); 1517 } 1518 doLog(lr, bundle); 1519 } 1520 1521 /** 1522 * Log a message, specifying source class, method, and resource bundle name, 1523 * with associated Throwable information. 1524 * <p> 1525 * If the logger is currently enabled for the given message 1526 * level then the given arguments are stored in a LogRecord 1527 * which is forwarded to all registered output handlers. 1528 * <p> 1529 * The msg string is localized using the named resource bundle. If the 1530 * resource bundle name is null, or an empty String or invalid 1531 * then the msg string is not localized. 1532 * <p> 1533 * Note that the thrown argument is stored in the LogRecord thrown 1534 * property, rather than the LogRecord parameters property. Thus it is 1535 * processed specially by output Formatters and is not treated 1536 * as a formatting parameter to the LogRecord message property. 1537 * 1538 * @param level One of the message level identifiers, e.g., SEVERE 1539 * @param sourceClass name of class that issued the logging request 1540 * @param sourceMethod name of method that issued the logging request 1541 * @param bundleName name of resource bundle to localize msg, 1542 * can be null 1543 * @param msg The string message (or a key in the message catalog) 1544 * @param thrown Throwable associated with log message. 1545 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1546 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1547 * java.lang.Throwable)} instead. 1548 */ 1549 @Deprecated 1550 public void logrb(Level level, String sourceClass, String sourceMethod, 1551 String bundleName, String msg, Throwable thrown) { 1552 if (!isLoggable(level)) { 1553 return; 1554 } 1555 LogRecord lr = new LogRecord(level, msg); 1556 lr.setSourceClassName(sourceClass); 1557 lr.setSourceMethodName(sourceMethod); 1558 lr.setThrown(thrown); 1559 doLog(lr, bundleName); 1560 } 1561 1562 /** 1563 * Log a message, specifying source class, method, and resource bundle, 1564 * with associated Throwable information. 1565 * <p> 1566 * If the logger is currently enabled for the given message 1567 * {@code level} then the given arguments are stored in a {@code LogRecord} 1568 * which is forwarded to all registered output handlers. 1569 * <p> 1570 * The {@code msg} string is localized using the given resource bundle. 1571 * If the resource bundle is {@code null}, then the {@code msg} string is not 1572 * localized. 1573 * <p> 1574 * Note that the {@code thrown} argument is stored in the {@code LogRecord} 1575 * {@code thrown} property, rather than the {@code LogRecord} 1576 * {@code parameters} property. Thus it is 1577 * processed specially by output {@code Formatter} objects and is not treated 1578 * as a formatting parameter to the {@code LogRecord} {@code message} property. 1579 * 1580 * @param level One of the message level identifiers, e.g., {@code SEVERE} 1581 * @param sourceClass Name of the class that issued the logging request 1582 * @param sourceMethod Name of the method that issued the logging request 1583 * @param bundle Resource bundle to localize {@code msg}, 1584 * can be {@code null} 1585 * @param msg The string message (or a key in the message catalog) 1586 * @param thrown Throwable associated with the log message. 1587 * @since 1.8 1588 */ 1589 public void logrb(Level level, String sourceClass, String sourceMethod, 1590 ResourceBundle bundle, String msg, Throwable thrown) { 1591 if (!isLoggable(level)) { 1592 return; 1593 } 1594 LogRecord lr = new LogRecord(level, msg); 1595 lr.setSourceClassName(sourceClass); 1596 lr.setSourceMethodName(sourceMethod); 1597 lr.setThrown(thrown); 1598 doLog(lr, bundle); 1599 } 1600 1601 /** 1602 * Log a message, specifying source class, method, and resource bundle, 1603 * with associated Throwable information. 1604 * <p> 1605 * If the logger is currently enabled for the given message 1606 * {@code level} then the given arguments are stored in a {@code LogRecord} 1607 * which is forwarded to all registered output handlers. 1608 * <p> 1609 * The {@code msg} string is localized using the given resource bundle. 1610 * If the resource bundle is {@code null}, then the {@code msg} string is not 1611 * localized. 1612 * <p> 1613 * Note that the {@code thrown} argument is stored in the {@code LogRecord} 1614 * {@code thrown} property, rather than the {@code LogRecord} 1615 * {@code parameters} property. Thus it is 1616 * processed specially by output {@code Formatter} objects and is not treated 1617 * as a formatting parameter to the {@code LogRecord} {@code message} 1618 * property. 1619 * <p> 1620 * @param level One of the message level identifiers, e.g., {@code SEVERE} 1621 * @param bundle Resource bundle to localize {@code msg}; 1622 * can be {@code null}. 1623 * @param msg The string message (or a key in the message catalog) 1624 * @param thrown Throwable associated with the log message. 1625 * @since 9 1626 */ 1627 public void logrb(Level level, ResourceBundle bundle, String msg, 1628 Throwable thrown) { 1629 if (!isLoggable(level)) { 1630 return; 1631 } 1632 LogRecord lr = new LogRecord(level, msg); 1633 lr.setThrown(thrown); 1634 doLog(lr, bundle); 1635 } 1636 1637 //====================================================================== 1638 // Start of convenience methods for logging method entries and returns. 1639 //====================================================================== 1640 1641 /** 1642 * Log a method entry. 1643 * <p> 1644 * This is a convenience method that can be used to log entry 1645 * to a method. A LogRecord with message "ENTRY", log level 1646 * FINER, and the given sourceMethod and sourceClass is logged. 1647 * 1648 * @param sourceClass name of class that issued the logging request 1649 * @param sourceMethod name of method that is being entered 1650 */ 1651 public void entering(String sourceClass, String sourceMethod) { 1652 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); 1653 } 1654 1655 /** 1656 * Log a method entry, with one parameter. 1657 * <p> 1658 * This is a convenience method that can be used to log entry 1659 * to a method. A LogRecord with message "ENTRY {0}", log level 1660 * FINER, and the given sourceMethod, sourceClass, and parameter 1661 * is logged. 1662 * 1663 * @param sourceClass name of class that issued the logging request 1664 * @param sourceMethod name of method that is being entered 1665 * @param param1 parameter to the method being entered 1666 */ 1667 public void entering(String sourceClass, String sourceMethod, Object param1) { 1668 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1); 1669 } 1670 1671 /** 1672 * Log a method entry, with an array of parameters. 1673 * <p> 1674 * This is a convenience method that can be used to log entry 1675 * to a method. A LogRecord with message "ENTRY" (followed by a 1676 * format {N} indicator for each entry in the parameter array), 1677 * log level FINER, and the given sourceMethod, sourceClass, and 1678 * parameters is logged. 1679 * 1680 * @param sourceClass name of class that issued the logging request 1681 * @param sourceMethod name of method that is being entered 1682 * @param params array of parameters to the method being entered 1683 */ 1684 public void entering(String sourceClass, String sourceMethod, Object params[]) { 1685 String msg = "ENTRY"; 1686 if (params == null ) { 1687 logp(Level.FINER, sourceClass, sourceMethod, msg); 1688 return; 1689 } 1690 if (!isLoggable(Level.FINER)) return; 1691 if (params.length > 0) { 1692 final StringBuilder b = new StringBuilder(msg); 1693 for (int i = 0; i < params.length; i++) { 1694 b.append(' ').append('{').append(i).append('}'); 1695 } 1696 msg = b.toString(); 1697 } 1698 logp(Level.FINER, sourceClass, sourceMethod, msg, params); 1699 } 1700 1701 /** 1702 * Log a method return. 1703 * <p> 1704 * This is a convenience method that can be used to log returning 1705 * from a method. A LogRecord with message "RETURN", log level 1706 * FINER, and the given sourceMethod and sourceClass is logged. 1707 * 1708 * @param sourceClass name of class that issued the logging request 1709 * @param sourceMethod name of the method 1710 */ 1711 public void exiting(String sourceClass, String sourceMethod) { 1712 logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); 1713 } 1714 1715 1716 /** 1717 * Log a method return, with result object. 1718 * <p> 1719 * This is a convenience method that can be used to log returning 1720 * from a method. A LogRecord with message "RETURN {0}", log level 1721 * FINER, and the gives sourceMethod, sourceClass, and result 1722 * object is logged. 1723 * 1724 * @param sourceClass name of class that issued the logging request 1725 * @param sourceMethod name of the method 1726 * @param result Object that is being returned 1727 */ 1728 public void exiting(String sourceClass, String sourceMethod, Object result) { 1729 logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); 1730 } 1731 1732 /** 1733 * Log throwing an exception. 1734 * <p> 1735 * This is a convenience method to log that a method is 1736 * terminating by throwing an exception. The logging is done 1737 * using the FINER level. 1738 * <p> 1739 * If the logger is currently enabled for the given message 1740 * level then the given arguments are stored in a LogRecord 1741 * which is forwarded to all registered output handlers. The 1742 * LogRecord's message is set to "THROW". 1743 * <p> 1744 * Note that the thrown argument is stored in the LogRecord thrown 1745 * property, rather than the LogRecord parameters property. Thus it is 1746 * processed specially by output Formatters and is not treated 1747 * as a formatting parameter to the LogRecord message property. 1748 * 1749 * @param sourceClass name of class that issued the logging request 1750 * @param sourceMethod name of the method. 1751 * @param thrown The Throwable that is being thrown. 1752 */ 1753 public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { 1754 if (!isLoggable(Level.FINER)) { 1755 return; 1756 } 1757 LogRecord lr = new LogRecord(Level.FINER, "THROW"); 1758 lr.setSourceClassName(sourceClass); 1759 lr.setSourceMethodName(sourceMethod); 1760 lr.setThrown(thrown); 1761 doLog(lr); 1762 } 1763 1764 //======================================================================= 1765 // Start of simple convenience methods using level names as method names 1766 //======================================================================= 1767 1768 /** 1769 * Log a SEVERE message. 1770 * <p> 1771 * If the logger is currently enabled for the SEVERE message 1772 * level then the given message is forwarded to all the 1773 * registered output Handler objects. 1774 * 1775 * @param msg The string message (or a key in the message catalog) 1776 */ 1777 public void severe(String msg) { 1778 log(Level.SEVERE, msg); 1779 } 1780 1781 /** 1782 * Log a WARNING message. 1783 * <p> 1784 * If the logger is currently enabled for the WARNING message 1785 * level then the given message is forwarded to all the 1786 * registered output Handler objects. 1787 * 1788 * @param msg The string message (or a key in the message catalog) 1789 */ 1790 public void warning(String msg) { 1791 log(Level.WARNING, msg); 1792 } 1793 1794 /** 1795 * Log an INFO message. 1796 * <p> 1797 * If the logger is currently enabled for the INFO message 1798 * level then the given message is forwarded to all the 1799 * registered output Handler objects. 1800 * 1801 * @param msg The string message (or a key in the message catalog) 1802 */ 1803 public void info(String msg) { 1804 log(Level.INFO, msg); 1805 } 1806 1807 /** 1808 * Log a CONFIG message. 1809 * <p> 1810 * If the logger is currently enabled for the CONFIG message 1811 * level then the given message is forwarded to all the 1812 * registered output Handler objects. 1813 * 1814 * @param msg The string message (or a key in the message catalog) 1815 */ 1816 public void config(String msg) { 1817 log(Level.CONFIG, msg); 1818 } 1819 1820 /** 1821 * Log a FINE message. 1822 * <p> 1823 * If the logger is currently enabled for the FINE message 1824 * level then the given message is forwarded to all the 1825 * registered output Handler objects. 1826 * 1827 * @param msg The string message (or a key in the message catalog) 1828 */ 1829 public void fine(String msg) { 1830 log(Level.FINE, msg); 1831 } 1832 1833 /** 1834 * Log a FINER message. 1835 * <p> 1836 * If the logger is currently enabled for the FINER message 1837 * level then the given message is forwarded to all the 1838 * registered output Handler objects. 1839 * 1840 * @param msg The string message (or a key in the message catalog) 1841 */ 1842 public void finer(String msg) { 1843 log(Level.FINER, msg); 1844 } 1845 1846 /** 1847 * Log a FINEST message. 1848 * <p> 1849 * If the logger is currently enabled for the FINEST message 1850 * level then the given message is forwarded to all the 1851 * registered output Handler objects. 1852 * 1853 * @param msg The string message (or a key in the message catalog) 1854 */ 1855 public void finest(String msg) { 1856 log(Level.FINEST, msg); 1857 } 1858 1859 //======================================================================= 1860 // Start of simple convenience methods using level names as method names 1861 // and use Supplier<String> 1862 //======================================================================= 1863 1864 /** 1865 * Log a SEVERE message, which is only to be constructed if the logging 1866 * level is such that the message will actually be logged. 1867 * <p> 1868 * If the logger is currently enabled for the SEVERE message 1869 * level then the message is constructed by invoking the provided 1870 * supplier function and forwarded to all the registered output 1871 * Handler objects. 1872 * 1873 * @param msgSupplier A function, which when called, produces the 1874 * desired log message 1875 * @since 1.8 1876 */ 1877 public void severe(Supplier<String> msgSupplier) { 1878 log(Level.SEVERE, msgSupplier); 1879 } 1880 1881 /** 1882 * Log a WARNING message, which is only to be constructed if the logging 1883 * level is such that the message will actually be logged. 1884 * <p> 1885 * If the logger is currently enabled for the WARNING message 1886 * level then the message is constructed by invoking the provided 1887 * supplier function and forwarded to all the registered output 1888 * Handler objects. 1889 * 1890 * @param msgSupplier A function, which when called, produces the 1891 * desired log message 1892 * @since 1.8 1893 */ 1894 public void warning(Supplier<String> msgSupplier) { 1895 log(Level.WARNING, msgSupplier); 1896 } 1897 1898 /** 1899 * Log a INFO message, which is only to be constructed if the logging 1900 * level is such that the message will actually be logged. 1901 * <p> 1902 * If the logger is currently enabled for the INFO message 1903 * level then the message is constructed by invoking the provided 1904 * supplier function and forwarded to all the registered output 1905 * Handler objects. 1906 * 1907 * @param msgSupplier A function, which when called, produces the 1908 * desired log message 1909 * @since 1.8 1910 */ 1911 public void info(Supplier<String> msgSupplier) { 1912 log(Level.INFO, msgSupplier); 1913 } 1914 1915 /** 1916 * Log a CONFIG message, which is only to be constructed if the logging 1917 * level is such that the message will actually be logged. 1918 * <p> 1919 * If the logger is currently enabled for the CONFIG message 1920 * level then the message is constructed by invoking the provided 1921 * supplier function and forwarded to all the registered output 1922 * Handler objects. 1923 * 1924 * @param msgSupplier A function, which when called, produces the 1925 * desired log message 1926 * @since 1.8 1927 */ 1928 public void config(Supplier<String> msgSupplier) { 1929 log(Level.CONFIG, msgSupplier); 1930 } 1931 1932 /** 1933 * Log a FINE message, which is only to be constructed if the logging 1934 * level is such that the message will actually be logged. 1935 * <p> 1936 * If the logger is currently enabled for the FINE message 1937 * level then the message is constructed by invoking the provided 1938 * supplier function and forwarded to all the registered output 1939 * Handler objects. 1940 * 1941 * @param msgSupplier A function, which when called, produces the 1942 * desired log message 1943 * @since 1.8 1944 */ 1945 public void fine(Supplier<String> msgSupplier) { 1946 log(Level.FINE, msgSupplier); 1947 } 1948 1949 /** 1950 * Log a FINER message, which is only to be constructed if the logging 1951 * level is such that the message will actually be logged. 1952 * <p> 1953 * If the logger is currently enabled for the FINER message 1954 * level then the message is constructed by invoking the provided 1955 * supplier function and forwarded to all the registered output 1956 * Handler objects. 1957 * 1958 * @param msgSupplier A function, which when called, produces the 1959 * desired log message 1960 * @since 1.8 1961 */ 1962 public void finer(Supplier<String> msgSupplier) { 1963 log(Level.FINER, msgSupplier); 1964 } 1965 1966 /** 1967 * Log a FINEST message, which is only to be constructed if the logging 1968 * level is such that the message will actually be logged. 1969 * <p> 1970 * If the logger is currently enabled for the FINEST message 1971 * level then the message is constructed by invoking the provided 1972 * supplier function and forwarded to all the registered output 1973 * Handler objects. 1974 * 1975 * @param msgSupplier A function, which when called, produces the 1976 * desired log message 1977 * @since 1.8 1978 */ 1979 public void finest(Supplier<String> msgSupplier) { 1980 log(Level.FINEST, msgSupplier); 1981 } 1982 1983 //================================================================ 1984 // End of convenience methods 1985 //================================================================ 1986 1987 /** 1988 * Set the log level specifying which message levels will be 1989 * logged by this logger. Message levels lower than this 1990 * value will be discarded. The level value Level.OFF 1991 * can be used to turn off logging. 1992 * <p> 1993 * If the new level is null, it means that this node should 1994 * inherit its level from its nearest ancestor with a specific 1995 * (non-null) level value. 1996 * 1997 * @param newLevel the new value for the log level (may be null) 1998 * @throws SecurityException if a security manager exists, 1999 * this logger is not anonymous, and the caller 2000 * does not have LoggingPermission("control"). 2001 */ 2002 public void setLevel(Level newLevel) throws SecurityException { 2003 checkPermission(); 2004 synchronized (treeLock) { 2005 config.setLevelObject(newLevel); 2006 updateEffectiveLevel(); 2007 } 2008 } 2009 2010 final boolean isLevelInitialized() { 2011 return config.levelObject != null; 2012 } 2013 2014 /** 2015 * Get the log Level that has been specified for this Logger. 2016 * The result may be null, which means that this logger's 2017 * effective level will be inherited from its parent. 2018 * 2019 * @return this Logger's level 2020 */ 2021 public Level getLevel() { 2022 return config.levelObject; 2023 } 2024 2025 /** 2026 * Check if a message of the given level would actually be logged 2027 * by this logger. This check is based on the Loggers effective level, 2028 * which may be inherited from its parent. 2029 * 2030 * @param level a message logging level 2031 * @return true if the given message level is currently being logged. 2032 */ 2033 public boolean isLoggable(Level level) { 2034 int levelValue = config.levelValue; 2035 if (level.intValue() < levelValue || levelValue == offValue) { 2036 return false; 2037 } 2038 return true; 2039 } 2040 2041 /** 2042 * Get the name for this logger. 2043 * @return logger name. Will be null for anonymous Loggers. 2044 */ 2045 public String getName() { 2046 return name; 2047 } 2048 2049 /** 2050 * Add a log Handler to receive logging messages. 2051 * <p> 2052 * By default, Loggers also send their output to their parent logger. 2053 * Typically the root Logger is configured with a set of Handlers 2054 * that essentially act as default handlers for all loggers. 2055 * 2056 * @param handler a logging Handler 2057 * @throws SecurityException if a security manager exists, 2058 * this logger is not anonymous, and the caller 2059 * does not have LoggingPermission("control"). 2060 */ 2061 public void addHandler(Handler handler) throws SecurityException { 2062 Objects.requireNonNull(handler); 2063 checkPermission(); 2064 config.addHandler(handler); 2065 } 2066 2067 /** 2068 * Remove a log Handler. 2069 * <P> 2070 * Returns silently if the given Handler is not found or is null 2071 * 2072 * @param handler a logging Handler 2073 * @throws SecurityException if a security manager exists, 2074 * this logger is not anonymous, and the caller 2075 * does not have LoggingPermission("control"). 2076 */ 2077 public void removeHandler(Handler handler) throws SecurityException { 2078 checkPermission(); 2079 if (handler == null) { 2080 return; 2081 } 2082 config.removeHandler(handler); 2083 } 2084 2085 /** 2086 * Get the Handlers associated with this logger. 2087 * 2088 * @return an array of all registered Handlers 2089 */ 2090 public Handler[] getHandlers() { 2091 return accessCheckedHandlers(); 2092 } 2093 2094 // This method should ideally be marked final - but unfortunately 2095 // it needs to be overridden by LogManager.RootLogger 2096 Handler[] accessCheckedHandlers() { 2097 return config.handlers.toArray(emptyHandlers); 2098 } 2099 2100 /** 2101 * Specify whether or not this logger should send its output 2102 * to its parent Logger. This means that any LogRecords will 2103 * also be written to the parent's Handlers, and potentially 2104 * to its parent, recursively up the namespace. 2105 * 2106 * @param useParentHandlers true if output is to be sent to the 2107 * logger's parent. 2108 * @throws SecurityException if a security manager exists, 2109 * this logger is not anonymous, and the caller 2110 * does not have LoggingPermission("control"). 2111 */ 2112 public void setUseParentHandlers(boolean useParentHandlers) { 2113 checkPermission(); 2114 config.setUseParentHandlers(useParentHandlers); 2115 } 2116 2117 /** 2118 * Discover whether or not this logger is sending its output 2119 * to its parent logger. 2120 * 2121 * @return true if output is to be sent to the logger's parent 2122 */ 2123 public boolean getUseParentHandlers() { 2124 return config.useParentHandlers; 2125 } 2126 2127 /** 2128 * Private utility method to map a resource bundle name to an 2129 * actual resource bundle, using a simple one-entry cache. 2130 * Returns null for a null name. 2131 * May also return null if we can't find the resource bundle and 2132 * there is no suitable previous cached value. 2133 * 2134 * @param name the ResourceBundle to locate 2135 * @param useCallersModule if true search using the caller's module. 2136 * @return ResourceBundle specified by name or null if not found 2137 */ 2138 private synchronized ResourceBundle findResourceBundle(String name, 2139 boolean useCallersModule) { 2140 // When this method is called from logrb, useCallersModule==false, and 2141 // the resource bundle 'name' is the argument provided to logrb. 2142 // It may, or may not be, equal to lb.resourceBundleName. 2143 // Otherwise, useCallersModule==true, and name is the resource bundle 2144 // name that is set (or will be set) in this logger. 2145 // 2146 // When useCallersModule is false, or when the caller's module is 2147 // null, or when the caller's module is an unnamed module, we look 2148 // first in the TCCL (or the System ClassLoader if the TCCL is null) 2149 // to locate the resource bundle. 2150 // 2151 // Otherwise, if useCallersModule is true, and the caller's module is not 2152 // null, and the caller's module is named, we look in the caller's module 2153 // to locate the resource bundle. 2154 // 2155 // Finally, if the caller's module is not null and is unnamed, and 2156 // useCallersModule is true, we look in the caller's module class loader 2157 // (unless we already looked there in step 1). 2158 2159 // Return a null bundle for a null name. 2160 if (name == null) { 2161 return null; 2162 } 2163 2164 Locale currentLocale = Locale.getDefault(); 2165 final LoggerBundle lb = loggerBundle; 2166 2167 // Normally we should hit on our simple one entry cache. 2168 if (lb.userBundle != null && 2169 name.equals(lb.resourceBundleName)) { 2170 return lb.userBundle; 2171 } else if (catalog != null && currentLocale.equals(catalogLocale) 2172 && name.equals(catalogName)) { 2173 return catalog; 2174 } 2175 2176 // Use the thread's context ClassLoader. If there isn't one, use the 2177 // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}. 2178 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 2179 if (cl == null) { 2180 cl = ClassLoader.getSystemClassLoader(); 2181 } 2182 2183 final Module callerModule = getCallerModule(); 2184 2185 // If useCallersModule is false, we are called by logrb, with a name 2186 // that is provided by the user. In that case we will look in the TCCL. 2187 // We also look in the TCCL if callerModule is null or unnamed. 2188 if (!useCallersModule || callerModule == null || !callerModule.isNamed()) { 2189 try { 2190 Module mod = cl.getUnnamedModule(); 2191 catalog = RbAccess.RB_ACCESS.getBundle(name, currentLocale, mod); 2192 catalogName = name; 2193 catalogLocale = currentLocale; 2194 return catalog; 2195 } catch (MissingResourceException ex) { 2196 // We can't find the ResourceBundle in the default 2197 // ClassLoader. Drop through. 2198 if (useCallersModule && callerModule != null) { 2199 try { 2200 // We are called by an unnamed module: try with the 2201 // unnamed module class loader: 2202 PrivilegedAction<ClassLoader> getModuleClassLoader = 2203 () -> callerModule.getClassLoader(); 2204 ClassLoader moduleCL = 2205 AccessController.doPrivileged(getModuleClassLoader); 2206 // moduleCL can be null if the logger is created by a class 2207 // appended to the bootclasspath. 2208 // If moduleCL is null we would use cl, but we already tried 2209 // that above (we first looked in the TCCL for unnamed 2210 // caller modules) - so there no point in trying again: we 2211 // won't find anything more this second time. 2212 // In this case just return null. 2213 if (moduleCL == cl || moduleCL == null) return null; 2214 2215 // we already tried the TCCL and found nothing - so try 2216 // with the module's loader this time. 2217 catalog = ResourceBundle.getBundle(name, currentLocale, 2218 moduleCL); 2219 catalogName = name; 2220 catalogLocale = currentLocale; 2221 return catalog; 2222 } catch (MissingResourceException x) { 2223 return null; // no luck 2224 } 2225 } else { 2226 return null; 2227 } 2228 } 2229 } else { 2230 // we should have: 2231 // useCallersModule && callerModule != null && callerModule.isNamed(); 2232 // Try with the caller's module 2233 try { 2234 // Use the caller's module 2235 catalog = RbAccess.RB_ACCESS.getBundle(name, currentLocale, callerModule); 2236 catalogName = name; 2237 catalogLocale = currentLocale; 2238 return catalog; 2239 } catch (MissingResourceException ex) { 2240 return null; // no luck 2241 } 2242 } 2243 } 2244 2245 private void setupResourceInfo(String name, Class<?> caller) { 2246 final Module module = caller == null ? null : caller.getModule(); 2247 setupResourceInfo(name, module); 2248 } 2249 2250 // Private utility method to initialize our one entry 2251 // resource bundle name cache and the callers Module 2252 // Note: for consistency reasons, we are careful to check 2253 // that a suitable ResourceBundle exists before setting the 2254 // resourceBundleName field. 2255 // Synchronized to prevent races in setting the fields. 2256 private synchronized void setupResourceInfo(String name, 2257 Module callerModule) { 2258 final LoggerBundle lb = loggerBundle; 2259 if (lb.resourceBundleName != null) { 2260 // this Logger already has a ResourceBundle 2261 2262 if (lb.resourceBundleName.equals(name)) { 2263 // the names match so there is nothing more to do 2264 return; 2265 } 2266 2267 // cannot change ResourceBundles once they are set 2268 throw new IllegalArgumentException( 2269 lb.resourceBundleName + " != " + name); 2270 } 2271 2272 if (name == null) { 2273 return; 2274 } 2275 2276 setCallerModuleRef(callerModule); 2277 2278 if (isSystemLogger && (callerModule != null && !isSystem(callerModule))) { 2279 checkPermission(); 2280 } 2281 2282 if (name.equals(SYSTEM_LOGGER_RB_NAME)) { 2283 loggerBundle = SYSTEM_BUNDLE; 2284 } else { 2285 ResourceBundle bundle = findResourceBundle(name, true); 2286 if (bundle == null) { 2287 // We've failed to find an expected ResourceBundle. 2288 // unset the caller's module since we were unable to find the 2289 // the bundle using it 2290 this.callerModuleRef = null; 2291 throw new MissingResourceException("Can't find " + name + " bundle from ", 2292 name, ""); 2293 } 2294 2295 loggerBundle = LoggerBundle.get(name, null); 2296 } 2297 } 2298 2299 /** 2300 * Sets a resource bundle on this logger. 2301 * All messages will be logged using the given resource bundle for its 2302 * specific {@linkplain ResourceBundle#getLocale locale}. 2303 * @param bundle The resource bundle that this logger shall use. 2304 * @throws NullPointerException if the given bundle is {@code null}. 2305 * @throws IllegalArgumentException if the given bundle doesn't have a 2306 * {@linkplain ResourceBundle#getBaseBundleName base name}, 2307 * or if this logger already has a resource bundle set but 2308 * the given bundle has a different base name. 2309 * @throws SecurityException if a security manager exists, 2310 * this logger is not anonymous, and the caller 2311 * does not have LoggingPermission("control"). 2312 * @since 1.8 2313 */ 2314 public void setResourceBundle(ResourceBundle bundle) { 2315 checkPermission(); 2316 2317 // Will throw NPE if bundle is null. 2318 final String baseName = bundle.getBaseBundleName(); 2319 2320 // bundle must have a name 2321 if (baseName == null || baseName.isEmpty()) { 2322 throw new IllegalArgumentException("resource bundle must have a name"); 2323 } 2324 2325 synchronized (this) { 2326 LoggerBundle lb = loggerBundle; 2327 final boolean canReplaceResourceBundle = lb.resourceBundleName == null 2328 || lb.resourceBundleName.equals(baseName); 2329 2330 if (!canReplaceResourceBundle) { 2331 throw new IllegalArgumentException("can't replace resource bundle"); 2332 } 2333 2334 2335 loggerBundle = LoggerBundle.get(baseName, bundle); 2336 } 2337 } 2338 2339 /** 2340 * Return the parent for this Logger. 2341 * <p> 2342 * This method returns the nearest extant parent in the namespace. 2343 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b" 2344 * has been created but no logger "a.b.c" exists, then a call of 2345 * getParent on the Logger "a.b.c.d" will return the Logger "a.b". 2346 * <p> 2347 * The result will be null if it is called on the root Logger 2348 * in the namespace. 2349 * 2350 * @return nearest existing parent Logger 2351 */ 2352 public Logger getParent() { 2353 // Note: this used to be synchronized on treeLock. However, this only 2354 // provided memory semantics, as there was no guarantee that the caller 2355 // would synchronize on treeLock (in fact, there is no way for external 2356 // callers to so synchronize). Therefore, we have made parent volatile 2357 // instead. 2358 return parent; 2359 } 2360 2361 /** 2362 * Set the parent for this Logger. This method is used by 2363 * the LogManager to update a Logger when the namespace changes. 2364 * <p> 2365 * It should not be called from application code. 2366 * 2367 * @param parent the new parent logger 2368 * @throws SecurityException if a security manager exists and if 2369 * the caller does not have LoggingPermission("control"). 2370 */ 2371 public void setParent(Logger parent) { 2372 if (parent == null) { 2373 throw new NullPointerException(); 2374 } 2375 2376 // check permission for all loggers, including anonymous loggers 2377 if (manager == null) { 2378 manager = LogManager.getLogManager(); 2379 } 2380 manager.checkPermission(); 2381 2382 doSetParent(parent); 2383 } 2384 2385 // Private method to do the work for parenting a child 2386 // Logger onto a parent logger. 2387 private void doSetParent(Logger newParent) { 2388 2389 // System.err.println("doSetParent \"" + getName() + "\" \"" 2390 // + newParent.getName() + "\""); 2391 2392 synchronized (treeLock) { 2393 2394 // Remove ourself from any previous parent. 2395 LogManager.LoggerWeakRef ref = null; 2396 if (parent != null) { 2397 // assert parent.kids != null; 2398 for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) { 2399 ref = iter.next(); 2400 Logger kid = ref.get(); 2401 if (kid == this) { 2402 // ref is used down below to complete the reparenting 2403 iter.remove(); 2404 break; 2405 } else { 2406 ref = null; 2407 } 2408 } 2409 // We have now removed ourself from our parents' kids. 2410 } 2411 2412 // Set our new parent. 2413 parent = newParent; 2414 if (parent.kids == null) { 2415 parent.kids = new ArrayList<>(2); 2416 } 2417 if (ref == null) { 2418 // we didn't have a previous parent 2419 ref = manager.new LoggerWeakRef(this); 2420 } 2421 ref.setParentRef(new WeakReference<>(parent)); 2422 parent.kids.add(ref); 2423 2424 // As a result of the reparenting, the effective level 2425 // may have changed for us and our children. 2426 updateEffectiveLevel(); 2427 2428 } 2429 } 2430 2431 // Package-level method. 2432 // Remove the weak reference for the specified child Logger from the 2433 // kid list. We should only be called from LoggerWeakRef.dispose(). 2434 final void removeChildLogger(LogManager.LoggerWeakRef child) { 2435 synchronized (treeLock) { 2436 for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) { 2437 LogManager.LoggerWeakRef ref = iter.next(); 2438 if (ref == child) { 2439 iter.remove(); 2440 return; 2441 } 2442 } 2443 } 2444 } 2445 2446 // Recalculate the effective level for this node and 2447 // recursively for our children. 2448 2449 private void updateEffectiveLevel() { 2450 // assert Thread.holdsLock(treeLock); 2451 2452 // Figure out our current effective level. 2453 int newLevelValue; 2454 final ConfigurationData cfg = config; 2455 final Level levelObject = cfg.levelObject; 2456 if (levelObject != null) { 2457 newLevelValue = levelObject.intValue(); 2458 } else { 2459 if (parent != null) { 2460 newLevelValue = parent.config.levelValue; 2461 } else { 2462 // This may happen during initialization. 2463 newLevelValue = Level.INFO.intValue(); 2464 } 2465 } 2466 2467 // If our effective value hasn't changed, we're done. 2468 if (cfg.levelValue == newLevelValue) { 2469 return; 2470 } 2471 2472 cfg.setLevelValue(newLevelValue); 2473 2474 // System.err.println("effective level: \"" + getName() + "\" := " + level); 2475 2476 // Recursively update the level on each of our kids. 2477 if (kids != null) { 2478 for (LogManager.LoggerWeakRef ref : kids) { 2479 Logger kid = ref.get(); 2480 if (kid != null) { 2481 kid.updateEffectiveLevel(); 2482 } 2483 } 2484 } 2485 } 2486 2487 2488 // Private method to get the potentially inherited 2489 // resource bundle and resource bundle name for this Logger. 2490 // This method never returns null. 2491 private LoggerBundle getEffectiveLoggerBundle() { 2492 final LoggerBundle lb = loggerBundle; 2493 if (lb.isSystemBundle()) { 2494 return SYSTEM_BUNDLE; 2495 } 2496 2497 // first take care of this logger 2498 final ResourceBundle b = getResourceBundle(); 2499 if (b != null && b == lb.userBundle) { 2500 return lb; 2501 } else if (b != null) { 2502 // either lb.userBundle is null or getResourceBundle() is 2503 // overriden 2504 final String rbName = getResourceBundleName(); 2505 return LoggerBundle.get(rbName, b); 2506 } 2507 2508 // no resource bundle was specified on this logger, look up the 2509 // parent stack. 2510 Logger target = this.parent; 2511 while (target != null) { 2512 final LoggerBundle trb = target.loggerBundle; 2513 if (trb.isSystemBundle()) { 2514 return SYSTEM_BUNDLE; 2515 } 2516 if (trb.userBundle != null) { 2517 return trb; 2518 } 2519 final String rbName = isSystemLogger 2520 // ancestor of a system logger is expected to be a system logger. 2521 // ignore resource bundle name if it's not. 2522 ? (target.isSystemLogger ? trb.resourceBundleName : null) 2523 : target.getResourceBundleName(); 2524 if (rbName != null) { 2525 return LoggerBundle.get(rbName, 2526 findResourceBundle(rbName, true)); 2527 } 2528 target = isSystemLogger ? target.parent : target.getParent(); 2529 } 2530 return NO_RESOURCE_BUNDLE; 2531 } 2532 2533 }