< prev index next >
jdk/src/java.base/share/classes/java/lang/System.java
Print this page
*** 28,52 ****
import java.lang.reflect.Executable;
import java.lang.annotation.Annotation;
import java.security.AccessControlContext;
import java.util.Properties;
import java.util.PropertyPermission;
- import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
- import java.security.AllPermission;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import sun.reflect.annotation.AnnotationType;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangAccess;;
import jdk.internal.misc.SharedSecrets;;
/**
* The <code>System</code> class contains several useful class fields
* and methods. It cannot be instantiated.
*
--- 28,56 ----
import java.lang.reflect.Executable;
import java.lang.annotation.Annotation;
import java.security.AccessControlContext;
import java.util.Properties;
import java.util.PropertyPermission;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
+ import java.util.Objects;
+ import java.util.ResourceBundle;
+ import java.util.function.Supplier;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import sun.reflect.annotation.AnnotationType;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangAccess;;
import jdk.internal.misc.SharedSecrets;;
+ import jdk.internal.logger.LoggerFinderLoader;
+ import jdk.internal.logger.LazyLoggers;
+ import jdk.internal.logger.LocalizedLoggerWrapper;
/**
* The <code>System</code> class contains several useful class fields
* and methods. It cannot be instantiated.
*
*** 942,951 ****
--- 946,1597 ----
return ProcessEnvironment.getenv();
}
/**
+ * {@code System.Logger} instances log messages that will be
+ * routed to the underlying logging framework the {@link System.LoggerFinder
+ * LoggerFinder} uses.
+ * <p>
+ * {@code System.Logger} instances are typically obtained from
+ * the {@link java.lang.System System} class, by calling
+ * {@link java.lang.System#getLogger(java.lang.String) System.getLogger(loggerName)}
+ * or {@link java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle)
+ * System.getLogger(loggerName, bundle)}.
+ *
+ * @see java.lang.System#getLogger(java.lang.String)
+ * @see java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle)
+ * @see java.lang.System.LoggerFinder
+ *
+ * @since 9
+ *
+ */
+ public interface Logger {
+
+ /**
+ * System {@linkplain Logger loggers} levels.
+ * <p>
+ * A level has a {@linkplain #getName() name} and {@linkplain
+ * #getSeverity() severity}.
+ * Level values are {@link #ALL}, {@link #TRACE}, {@link #DEBUG},
+ * {@link #INFO}, {@link #WARNING}, {@link #ERROR}, {@link #OFF},
+ * by order of increasing severity.
+ * <br>
+ * {@link #ALL} and {@link #OFF}
+ * are simple markers with severities mapped respectively to
+ * {@link java.lang.Integer#MIN_VALUE Integer.MIN_VALUE} and
+ * {@link java.lang.Integer#MAX_VALUE Integer.MAX_VALUE}.
+ * <p>
+ * <b>Severity values and Mapping to {@code java.util.logging.Level}.</b>
+ * <p>
+ * {@linkplain System.Logger.Level System logger levels} are mapped to
+ * {@linkplain java.util.logging.Level java.util.logging levels}
+ * of corresponding severity.
+ * <br>The mapping is as follows:
+ * <br><br>
+ * <table border="1">
+ * <caption>System.Logger Severity Level Mapping</caption>
+ * <tr><td><b>System.Logger Levels</b></td>
+ * <td>{@link Logger.Level#ALL ALL}</td>
+ * <td>{@link Logger.Level#TRACE TRACE}</td>
+ * <td>{@link Logger.Level#DEBUG DEBUG}</td>
+ * <td>{@link Logger.Level#INFO INFO}</td>
+ * <td>{@link Logger.Level#WARNING WARNING}</td>
+ * <td>{@link Logger.Level#ERROR ERROR}</td>
+ * <td>{@link Logger.Level#OFF OFF}</td>
+ * </tr>
+ * <tr><td><b>java.util.logging Levels</b></td>
+ * <td>{@link java.util.logging.Level#ALL ALL}</td>
+ * <td>{@link java.util.logging.Level#FINER FINER}</td>
+ * <td>{@link java.util.logging.Level#FINE FINE}</td>
+ * <td>{@link java.util.logging.Level#INFO INFO}</td>
+ * <td>{@link java.util.logging.Level#WARNING WARNING}</td>
+ * <td>{@link java.util.logging.Level#SEVERE SEVERE}</td>
+ * <td>{@link java.util.logging.Level#OFF OFF}</td>
+ * </tr>
+ * </table>
+ *
+ * @since 9
+ *
+ * @see java.lang.System.LoggerFinder
+ * @see java.lang.System.Logger
+ */
+ public enum Level {
+
+ // for convenience, we're reusing java.util.logging.Level int values
+ // the mapping logic in sun.util.logging.PlatformLogger depends
+ // on this.
+ /**
+ * A marker to indicate that all levels are enabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MIN_VALUE}.
+ */
+ ALL(Integer.MIN_VALUE), // typically mapped to/from j.u.l.Level.ALL
+ /**
+ * {@code TRACE} level: usually used to log diagnostic information.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 400}.
+ */
+ TRACE(400), // typically mapped to/from j.u.l.Level.FINER
+ /**
+ * {@code DEBUG} level: usually used to log debug information traces.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 500}.
+ */
+ DEBUG(500), // typically mapped to/from j.u.l.Level.FINEST/FINE/CONFIG
+ /**
+ * {@code INFO} level: usually used to log information messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 800}.
+ */
+ INFO(800), // typically mapped to/from j.u.l.Level.INFO
+ /**
+ * {@code WARNING} level: usually used to log warning messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 900}.
+ */
+ WARNING(900), // typically mapped to/from j.u.l.Level.WARNING
+ /**
+ * {@code ERROR} level: usually used to log error messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 1000}.
+ */
+ ERROR(1000), // typically mapped to/from j.u.l.Level.SEVERE
+ /**
+ * A marker to indicate that all levels are disabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MAX_VALUE}.
+ */
+ OFF(Integer.MAX_VALUE); // typically mapped to/from j.u.l.Level.OFF
+
+ private final int severity;
+
+ private Level(int severity) {
+ this.severity = severity;
+ }
+
+ /**
+ * Returns the name of this level.
+ * @return this level {@linkplain #name()}.
+ */
+ public final String getName() {
+ return name();
+ }
+
+ /**
+ * Returns the severity of this level.
+ * A higher severity means a more severe condition.
+ * @return this level severity.
+ */
+ public final int getSeverity() {
+ return severity;
+ }
+ }
+
+ /**
+ * Returns the name of this logger.
+ *
+ * @return the logger name.
+ */
+ public String getName();
+
+ /**
+ * Checks if a message of the given level would be logged by
+ * this logger.
+ *
+ * @param level the log message level.
+ * @return {@code true} if the given log message level is currently
+ * being logged.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public boolean isLoggable(Level level);
+
+ /**
+ * Logs a message.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg) {
+ log(level, (ResourceBundle) null, msg, (Object[]) null);
+ }
+
+ /**
+ * Logs a lazily supplied message.
+ * <p>
+ * If the logger is currently enabled for the given log message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param msgSupplier a supplier function that produces a message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null},
+ * or {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier<String> msgSupplier) {
+ Objects.requireNonNull(msgSupplier);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ log(level, (ResourceBundle) null, msgSupplier.get(), (Object[]) null);
+ }
+ }
+
+ /**
+ * Logs a message produced from the given object.
+ * <p>
+ * If the logger is currently enabled for the given log message level then
+ * a message is logged that, by default, is the result produced from
+ * calling toString on the given object.
+ * Otherwise, the object is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, obj.toString(), (Object[])null);}
+ *
+ * @param level the log message level.
+ * @param obj the object to log.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@code obj} is {@code null}.
+ */
+ public default void log(Level level, Object obj) {
+ Objects.requireNonNull(obj);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ this.log(level, (ResourceBundle) null, obj.toString(), (Object[]) null);
+ }
+ }
+
+ /**
+ * Logs a message associated with a given throwable.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, thrown);}
+ *
+ * @param level the log message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg, Throwable thrown) {
+ this.log(level, null, msg, thrown);
+ }
+
+ /**
+ * Logs a lazily supplied message associated with a given throwable.
+ * <p>
+ * If the logger is currently enabled for the given log message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), thrown);}
+ *
+ * @param level one of the log message level identifiers.
+ * @param msgSupplier a supplier function that produces a message.
+ * @param thrown a {@code Throwable} associated with log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier<String> msgSupplier,
+ Throwable thrown) {
+ Objects.requireNonNull(msgSupplier);
+ if (isLoggable(Objects.requireNonNull(level))) {
+ this.log(level, null, msgSupplier.get(), thrown);
+ }
+ }
+
+ /**
+ * Logs a message with an optional list of parameters.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, format, params);}
+ *
+ * @param level one of the log message level identifiers.
+ * @param format the string message format in {@link
+ * java.text.MessageFormat} format, (or a key in the message
+ * catalog, if this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}); can be {@code null}.
+ * @param params an optional list of parameters to the message (may be
+ * none).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String format, Object... params) {
+ this.log(level, null, format, params);
+ }
+
+ /**
+ * Logs a localized message associated with a given throwable.
+ * <p>
+ * If the given resource bundle is non-{@code null}, the {@code msg}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code msg} string is not localized.
+ *
+ * @param level the log message level.
+ * @param bundle a resource bundle to localize {@code msg}; can be
+ * {@code null}.
+ * @param msg the string message (or a key in the message catalog,
+ * if {@code bundle} is not {@code null}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String msg,
+ Throwable thrown);
+
+ /**
+ * Logs a message with resource bundle and an optional list of
+ * parameters.
+ * <p>
+ * If the given resource bundle is non-{@code null}, the {@code format}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code format} string is not localized.
+ *
+ * @param level the log message level.
+ * @param bundle a resource bundle to localize {@code format}; can be
+ * {@code null}.
+ * @param format the string message format in {@link
+ * java.text.MessageFormat} format, (or a key in the message
+ * catalog if {@code bundle} is not {@code null}); can be {@code null}.
+ * @param params an optional list of parameters to the message (may be
+ * none).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String format,
+ Object... params);
+
+
+ }
+
+ /**
+ * The {@code LoggerFinder} service is responsible for creating, managing,
+ * and configuring loggers to the underlying framework it uses.
+ * <p>
+ * A logger finder is a concrete implementation of this class that has a
+ * zero-argument constructor and implements the abstract methods defined
+ * by this class.
+ * The loggers returned from a logger finder are capable of routing log
+ * messages to the logging backend this provider supports.
+ * A given invocation of the Java Runtime maintains a single
+ * system-wide LoggerFinder instance that is loaded as follows:
+ * <ul>
+ * <li>First it finds any custom {@code LoggerFinder} provider
+ * using the {@link java.util.ServiceLoader} facility with the
+ * {@linkplain ClassLoader#getSystemClassLoader() system class
+ * loader}.</li>
+ * <li>If no {@code LoggerFinder} provider is found, the system default
+ * {@code LoggerFinder} implementation will be used.</li>
+ * </ul>
+ * <p>
+ * An application can replace the logging backend
+ * <i>even when the java.logging module is present</i>, by simply providing
+ * and declaring an implementation of the {@link LoggerFinder} service.
+ * <p>
+ * <b>Default Implementation</b>
+ * <p>
+ * The system default {@code LoggerFinder} implementation uses
+ * {@code java.util.logging} as the backend framework when the
+ * {@code java.logging} module is present.
+ * It returns a {@linkplain System.Logger logger} instance
+ * that will route log messages to a {@link java.util.logging.Logger
+ * java.util.logging.Logger}. Otherwise, if {@code java.logging} is not
+ * present, the default implementation will return a simple logger
+ * instance that will route log messages of {@code INFO} level and above to
+ * the console ({@code System.err}).
+ * <p>
+ * <b>Logging Configuration</b>
+ * <p>
+ * {@linkplain Logger Logger} instances obtained from the
+ * {@code LoggerFinder} factory methods are not directly configurable by
+ * the application. Configuration is the responsibility of the underlying
+ * logging backend, and usually requires using APIs specific to that backend.
+ * <p>For the default {@code LoggerFinder} implementation
+ * using {@code java.util.logging} as its backend, refer to
+ * {@link java.util.logging java.util.logging} for logging configuration.
+ * For the default {@code LoggerFinder} implementation returning simple loggers
+ * when the {@code java.logging} module is absent, the configuration
+ * is implementation dependent.
+ * <p>
+ * Usually an application that uses a logging framework will log messages
+ * through a logger facade defined (or supported) by that framework.
+ * Applications that wish to use an external framework should log
+ * through the facade associated with that framework.
+ * <p>
+ * A system class that needs to log messages will typically obtain
+ * a {@link System.Logger} instance to route messages to the logging
+ * framework selected by the application.
+ * <p>
+ * Libraries and classes that only need loggers to produce log messages
+ * should not attempt to configure loggers by themselves, as that
+ * would make them dependent from a specific implementation of the
+ * {@code LoggerFinder} service.
+ * <p>
+ * In addition, when a security manager is present, loggers provided to
+ * system classes should not be directly configurable through the logging
+ * backend without requiring permissions.
+ * <br>
+ * It is the responsibility of the provider of
+ * the concrete {@code LoggerFinder} implementation to ensure that
+ * these loggers are not configured by untrusted code without proper
+ * permission checks, as configuration performed on such loggers usually
+ * affects all applications in the same Java Runtime.
+ * <p>
+ * <b>Message Levels and Mapping to backend levels</b>
+ * <p>
+ * A logger finder is responsible for mapping from a {@code
+ * System.Logger.Level} to a level supported by the logging backend it uses.
+ * <br>The default LoggerFinder using {@code java.util.logging} as the backend
+ * maps {@code System.Logger} levels to
+ * {@linkplain java.util.logging.Level java.util.logging} levels
+ * of corresponding severity - as described in {@link Logger.Level
+ * Logger.Level}.
+ *
+ * @see java.lang.System
+ * @see java.lang.System.Logger
+ *
+ * @since 9
+ */
+ public static abstract class LoggerFinder {
+ /**
+ * The {@code RuntimePermission("loggerFinder")} is
+ * necessary to subclass and instantiate the {@code LoggerFinder} class,
+ * as well as to obtain loggers from an instance of that class.
+ */
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ /**
+ * Creates a new instance of {@code LoggerFinder}.
+ *
+ * @implNote It is recommended that a {@code LoggerFinder} service
+ * implementation does not perform any heavy initialization in its
+ * constructor, in order to avoid possible risks of deadlock or class
+ * loading cycles during the instantiation of the service provider.
+ *
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ protected LoggerFinder() {
+ this(checkPermission());
+ }
+
+ private LoggerFinder(Void unused) {
+ // nothing to do.
+ }
+
+ private static Void checkPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return null;
+ }
+
+ /**
+ * Returns an instance of {@link Logger Logger}
+ * for the given {@code caller}.
+ *
+ * @param name the name of the logger.
+ * @param caller the class for which the logger is being requested;
+ * can be {@code null}.
+ *
+ * @return a {@link Logger logger} suitable for the given caller's
+ * use.
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public abstract Logger getLogger(String name, /* Module */ Class<?> caller);
+
+ /**
+ * Returns a localizable instance of {@link Logger Logger}
+ * for the given {@code caller}.
+ * The returned logger will use the provided resource bundle for
+ * message localization.
+ *
+ * @implSpec By default, this method calls {@link
+ * #getLogger(java.lang.String, java.lang.Class)
+ * this.getLogger(name, caller)} to obtain a logger, then wraps that
+ * logger in a {@link Logger} instance where all methods that do not
+ * take a {@link ResourceBundle} as parameter are redirected to one
+ * which does - passing the given {@code bundle} for
+ * localization. So for instance, a call to {@link
+ * Logger#log(Level, String) Logger.log(Level.INFO, msg)}
+ * will end up as a call to {@link
+ * Logger#log(Level, ResourceBundle, String, Object...)
+ * Logger.log(Level.INFO, bundle, msg, (Object[])null)} on the wrapped
+ * logger instance.
+ * Note however that by default, string messages returned by {@link
+ * java.util.function.Supplier Supplier<String>} will not be
+ * localized, as it is assumed that such strings are messages which are
+ * already constructed, rather than keys in a resource bundle.
+ * <p>
+ * An implementation of {@code LoggerFinder} may override this method,
+ * for example, when the underlying logging backend provides its own
+ * mechanism for localizing log messages, then such a
+ * {@code LoggerFinder} would be free to return a logger
+ * that makes direct use of the mechanism provided by the backend.
+ *
+ * @param name the name of the logger.
+ * @param bundle a resource bundle; can be {@code null}.
+ * @param caller the class for which the logger is being requested.
+ * @return an instance of {@link Logger Logger} which will use the
+ * provided resource bundle for message localization.
+ *
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle,
+ /* Module */ Class<?> caller) {
+ return new LocalizedLoggerWrapper<>(getLogger(name, caller), bundle);
+ }
+
+ /**
+ * Returns the {@code LoggerFinder} instance. There is one
+ * single system-wide {@code LoggerFinder} instance in
+ * the Java Runtime. See the class specification of how the
+ * {@link LoggerFinder LoggerFinder} implementation is located and
+ * loaded.
+
+ * @return the {@link LoggerFinder LoggerFinder} instance.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public static LoggerFinder getLoggerFinder() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return accessProvider();
+ }
+
+
+ private static volatile LoggerFinder service;
+ static LoggerFinder accessProvider() {
+ // We do not need to synchronize: LoggerFinderLoader will
+ // always return the same instance, so if we don't have it,
+ // just fetch it again.
+ if (service == null) {
+ PrivilegedAction<LoggerFinder> pa =
+ () -> LoggerFinderLoader.getLoggerFinder();
+ service = AccessController.doPrivileged(pa, null,
+ LOGGERFINDER_PERMISSION);
+ }
+ return service;
+ }
+
+ }
+
+
+ /**
+ * Returns an instance of {@link Logger Logger} for the caller's
+ * use.
+ *
+ * @implSpec
+ * Instances returned by this method route messages to loggers
+ * obtained by calling {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class)
+ * LoggerFinder.getLogger(name, caller)}.
+ *
+ * @apiNote
+ * This method may defer calling the {@link
+ * LoggerFinder#getLogger(java.lang.String, java.lang.Class)
+ * LoggerFinder.getLogger} method to create an actual logger supplied by
+ * the logging backend, for instance, to allow loggers to be obtained during
+ * the system initialization time.
+ *
+ * @param name the name of the logger.
+ * @return an instance of {@link Logger} that can be used by the calling
+ * class.
+ * @throws NullPointerException if {@code name} is {@code null}.
+ */
+ @CallerSensitive
+ public static Logger getLogger(String name) {
+ Objects.requireNonNull(name);
+ final Class<?> caller = Reflection.getCallerClass();
+ return LazyLoggers.getLogger(name, caller);
+ }
+
+ /**
+ * Returns a localizable instance of {@link Logger
+ * Logger} for the caller's use.
+ * The returned logger will use the provided resource bundle for message
+ * localization.
+ *
+ * @implSpec
+ * The returned logger will perform message localization as specified
+ * by {@link LoggerFinder#getLocalizedLogger(java.lang.String,
+ * java.util.ResourceBundle, java.lang.Class)
+ * LoggerFinder.getLocalizedLogger(name, bundle, caller}.
+ *
+ * @apiNote
+ * This method is intended to be used after the system is fully initialized.
+ * This method may trigger the immediate loading and initialization
+ * of the {@link LoggerFinder} service, which may cause issues if the
+ * Java Runtime is not ready to initialize the concrete service
+ * implementation yet.
+ * System classes which may be loaded early in the boot sequence and
+ * need to log localized messages should create a logger using
+ * {@link #getLogger(java.lang.String)} and then use the log methods that
+ * take a resource bundle as parameter.
+ *
+ * @param name the name of the logger.
+ * @param bundle a resource bundle.
+ * @return an instance of {@link Logger} which will use the provided
+ * resource bundle for message localization.
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code bundle} is {@code null}.
+ */
+ @CallerSensitive
+ public static Logger getLogger(String name, ResourceBundle bundle) {
+ final ResourceBundle rb = Objects.requireNonNull(bundle);
+ Objects.requireNonNull(name);
+ final Class<?> caller = Reflection.getCallerClass();
+ final SecurityManager sm = System.getSecurityManager();
+ // We don't use LazyLoggers if a resource bundle is specified.
+ // Bootstrap sensitive classes in the JDK do not use resource bundles
+ // when logging. This could be revisited later, if it needs to.
+ if (sm != null) {
+ return AccessController.doPrivileged((PrivilegedAction<Logger>)
+ () -> LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller),
+ null,
+ LoggerFinder.LOGGERFINDER_PERMISSION);
+ }
+ return LoggerFinder.accessProvider().getLocalizedLogger(name, rb, caller);
+ }
+
+ /**
* Terminates the currently running Java Virtual Machine. The
* argument serves as a status code; by convention, a nonzero status
* code indicates abnormal termination.
* <p>
* This method calls the <code>exit</code> method in class
< prev index next >