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