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