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