/*
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.logging;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.function.Supplier;
import jdk.internal.logger.LazyLoggers;
import jdk.internal.logger.LoggerWrapper;
Platform logger provides an API for the JRE components to log messages. This enables the runtime components to eliminate the static dependency of the logging facility and also defers the java.util.logging initialization until it is enabled. In addition, the PlatformLogger API can be used if the logging module does not exist. If the logging facility is not enabled, the platform loggers will output log messages per the default logging configuration (see below). In this implementation, it does not log the the stack frame information issuing the log message. When the logging facility is enabled (at startup or runtime), the backend logger will be created for each platform logger and all log messages will be forwarded to the Logger to handle. The PlatformLogger uses an underlying PlatformLogger.Bridge instance obtained by calling PlatformLogger.Bridge.convert(
jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))
. Logging facility is "enabled" when one of the following conditions is met: 1) ServiceLoader.load(LoggerFinder.class
, ClassLoader.getSystemClassLoader()).iterator().hasNext(). 2) ServiceLoader.loadInstalled(DefaultLoggerFinder
).iterator().hasNext(), and 2.1) a system property "java.util.logging.config.class" or "java.util.logging.config.file" is set or 2.2) java.util.logging.LogManager or java.util.logging.Logger is referenced that will trigger the logging initialization. Default logging configuration: No LoggerFinder service implementation declared global logging level = INFO handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = INFO java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter Limitation: <JAVA_HOME>/conf/logging.properties
is the system-wide logging configuration defined in the specification and read in the default case to configure any java.util.logging.Logger instances. Platform loggers will not detect if <JAVA_HOME>/conf/logging.properties
is modified. In other words, unless the java.util.logging API is used at runtime or the logging system properties is set, the platform loggers will use the default setting described above. The platform loggers are designed for JDK developers use and this limitation can be workaround with setting -Djava.util.logging.config.file system property.
Calling PlatformLogger.setLevel will not work when there is a custom LoggerFinder installed - and as a consequence setLevel
is now deprecated. Since: 1.7
/**
* Platform logger provides an API for the JRE components to log
* messages. This enables the runtime components to eliminate the
* static dependency of the logging facility and also defers the
* java.util.logging initialization until it is enabled.
* In addition, the PlatformLogger API can be used if the logging
* module does not exist.
*
* If the logging facility is not enabled, the platform loggers
* will output log messages per the default logging configuration
* (see below). In this implementation, it does not log the
* the stack frame information issuing the log message.
*
* When the logging facility is enabled (at startup or runtime),
* the backend logger will be created for each platform
* logger and all log messages will be forwarded to the Logger
* to handle.
*
* The PlatformLogger uses an underlying PlatformLogger.Bridge instance
* obtained by calling {@link PlatformLogger.Bridge#convert PlatformLogger.Bridge.convert(}
* {@link jdk.internal.logger.LazyLoggers#getLazyLogger(java.lang.String, java.lang.Class)
* jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))}.
*
* Logging facility is "enabled" when one of the following
* conditions is met:
* 1) ServiceLoader.load({@link java.lang.System.LoggerFinder LoggerFinder.class},
* ClassLoader.getSystemClassLoader()).iterator().hasNext().
* 2) ServiceLoader.loadInstalled({@link jdk.internal.logger.DefaultLoggerFinder}).iterator().hasNext(),
* and 2.1) a system property "java.util.logging.config.class" or
* "java.util.logging.config.file" is set
* or 2.2) java.util.logging.LogManager or java.util.logging.Logger
* is referenced that will trigger the logging initialization.
*
* Default logging configuration:
*
* No LoggerFinder service implementation declared
* global logging level = INFO
* handlers = java.util.logging.ConsoleHandler
* java.util.logging.ConsoleHandler.level = INFO
* java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
*
* Limitation:
* {@code <JAVA_HOME>/conf/logging.properties} is the system-wide logging
* configuration defined in the specification and read in the
* default case to configure any java.util.logging.Logger instances.
* Platform loggers will not detect if {@code <JAVA_HOME>/conf/logging.properties}
* is modified. In other words, unless the java.util.logging API
* is used at runtime or the logging system properties is set,
* the platform loggers will use the default setting described above.
* The platform loggers are designed for JDK developers use and
* this limitation can be workaround with setting
* -Djava.util.logging.config.file system property.
* <br>
* Calling PlatformLogger.setLevel will not work when there is a custom
* LoggerFinder installed - and as a consequence {@link #setLevel setLevel}
* is now deprecated.
*
* @since 1.7
*/
public class PlatformLogger {
PlatformLogger logging levels.
/**
* PlatformLogger logging levels.
*/
public static enum Level {
// The name and value must match that of {@code java.util.logging.Level}s.
// Declare in ascending order of the given value for binary search.
ALL(System.Logger.Level.ALL),
FINEST(System.Logger.Level.TRACE),
FINER(System.Logger.Level.TRACE),
FINE(System.Logger.Level.DEBUG),
CONFIG(System.Logger.Level.DEBUG),
INFO(System.Logger.Level.INFO),
WARNING(System.Logger.Level.WARNING),
SEVERE(System.Logger.Level.ERROR),
OFF(System.Logger.Level.OFF);
final System.Logger.Level systemLevel;
Level(System.Logger.Level systemLevel) {
this.systemLevel = systemLevel;
}
// The integer values must match that of {@code java.util.logging.Level}
// objects.
private static final int SEVERITY_OFF = Integer.MAX_VALUE;
private static final int SEVERITY_SEVERE = 1000;
private static final int SEVERITY_WARNING = 900;
private static final int SEVERITY_INFO = 800;
private static final int SEVERITY_CONFIG = 700;
private static final int SEVERITY_FINE = 500;
private static final int SEVERITY_FINER = 400;
private static final int SEVERITY_FINEST = 300;
private static final int SEVERITY_ALL = Integer.MIN_VALUE;
// ascending order for binary search matching the list of enum constants
private static final int[] LEVEL_VALUES = new int[] {
SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,
SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,
SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF
};
public System.Logger.Level systemLevel() {
return systemLevel;
}
public int intValue() {
return LEVEL_VALUES[this.ordinal()];
}
Maps a severity value to an effective logger level.
Params: - level – The severity of the messages that should be
logged with a logger set to the returned level.
Returns: The effective logger level, which is the nearest Level value
whose severity is greater or equal to the given level.
For level > SEVERE (OFF excluded), return SEVERE.
/**
* Maps a severity value to an effective logger level.
* @param level The severity of the messages that should be
* logged with a logger set to the returned level.
* @return The effective logger level, which is the nearest Level value
* whose severity is greater or equal to the given level.
* For level > SEVERE (OFF excluded), return SEVERE.
*/
public static Level valueOf(int level) {
switch (level) {
// ordering per the highest occurrences in the jdk source
// finest, fine, finer, info first
case SEVERITY_FINEST : return Level.FINEST;
case SEVERITY_FINE : return Level.FINE;
case SEVERITY_FINER : return Level.FINER;
case SEVERITY_INFO : return Level.INFO;
case SEVERITY_WARNING : return Level.WARNING;
case SEVERITY_CONFIG : return Level.CONFIG;
case SEVERITY_SEVERE : return Level.SEVERE;
case SEVERITY_OFF : return Level.OFF;
case SEVERITY_ALL : return Level.ALL;
}
// return the nearest Level value >= the given level,
// for level > SEVERE, return SEVERE and exclude OFF
int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);
return values()[i >= 0 ? i : (-i-1)];
}
}
The PlatformLogger.Bridge interface is implemented by the System.Logger
objects returned by our default JUL provider - so that JRE classes using
PlatformLogger see no difference when JUL is the actual backend.
PlatformLogger is now only a thin adaptation layer over the same
loggers than returned by java.lang.System.getLogger(String name).
The recommendation for JRE classes going forward is to use
java.lang.System.getLogger(String name), which will
use Lazy Loggers when possible and necessary.
/**
*
* The PlatformLogger.Bridge interface is implemented by the System.Logger
* objects returned by our default JUL provider - so that JRE classes using
* PlatformLogger see no difference when JUL is the actual backend.
*
* PlatformLogger is now only a thin adaptation layer over the same
* loggers than returned by java.lang.System.getLogger(String name).
*
* The recommendation for JRE classes going forward is to use
* java.lang.System.getLogger(String name), which will
* use Lazy Loggers when possible and necessary.
*
*/
public static interface Bridge {
Gets the name for this platform logger.
Returns: the name of the platform logger.
/**
* Gets the name for this platform logger.
* @return the name of the platform logger.
*/
public String getName();
Returns true if a message of the given level would actually
be logged by this logger.
Params: - level – the level
Returns: whether a message of that level would be logged
/**
* Returns true if a message of the given level would actually
* be logged by this logger.
* @param level the level
* @return whether a message of that level would be logged
*/
public boolean isLoggable(Level level);
public boolean isEnabled();
public void log(Level level, String msg);
public void log(Level level, String msg, Throwable thrown);
public void log(Level level, String msg, Object... params);
public void log(Level level, Supplier<String> msgSupplier);
public void log(Level level, Throwable thrown, Supplier<String> msgSupplier);
public void logp(Level level, String sourceClass, String sourceMethod, String msg);
public void logp(Level level, String sourceClass, String sourceMethod,
Supplier<String> msgSupplier);
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Object... params);
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Throwable thrown);
public void logp(Level level, String sourceClass, String sourceMethod,
Throwable thrown, Supplier<String> msgSupplier);
public void logrb(Level level, String sourceClass, String sourceMethod,
ResourceBundle bundle, String msg, Object... params);
public void logrb(Level level, String sourceClass, String sourceMethod,
ResourceBundle bundle, String msg, Throwable thrown);
public void logrb(Level level, ResourceBundle bundle, String msg,
Object... params);
public void logrb(Level level, ResourceBundle bundle, String msg,
Throwable thrown);
public static Bridge convert(System.Logger logger) {
if (logger instanceof PlatformLogger.Bridge) {
return (Bridge) logger;
} else {
return new LoggerWrapper<>(logger);
}
}
}
The PlatformLogger.ConfigurableBridge
interface is used to implement the deprecated PlatformLogger.setLevel
method. PlatformLogger is now only a thin adaptation layer over the same loggers than returned by java.lang.System.getLogger(String name). The recommendation for JRE classes going forward is to use java.lang.System.getLogger(String name), which will use Lazy Loggers when possible and necessary. /**
* The {@code PlatformLogger.ConfigurableBridge} interface is used to
* implement the deprecated {@link PlatformLogger#setLevel} method.
*
* PlatformLogger is now only a thin adaptation layer over the same
* loggers than returned by java.lang.System.getLogger(String name).
*
* The recommendation for JRE classes going forward is to use
* java.lang.System.getLogger(String name), which will
* use Lazy Loggers when possible and necessary.
*
*/
public static interface ConfigurableBridge {
public abstract class LoggerConfiguration {
public abstract Level getPlatformLevel();
public abstract void setPlatformLevel(Level level);
}
public default LoggerConfiguration getLoggerConfiguration() {
return null;
}
public static LoggerConfiguration getLoggerConfiguration(PlatformLogger.Bridge logger) {
if (logger instanceof PlatformLogger.ConfigurableBridge) {
return ((ConfigurableBridge) logger).getLoggerConfiguration();
} else {
return null;
}
}
}
// Table of known loggers. Maps names to PlatformLoggers.
private static final Map<String,WeakReference<PlatformLogger>> loggers =
new HashMap<>();
Returns a PlatformLogger of a given name.
Params: - name – the name of the logger
Returns: a PlatformLogger
/**
* Returns a PlatformLogger of a given name.
* @param name the name of the logger
* @return a PlatformLogger
*/
public static synchronized PlatformLogger getLogger(String name) {
PlatformLogger log = null;
WeakReference<PlatformLogger> ref = loggers.get(name);
if (ref != null) {
log = ref.get();
}
if (log == null) {
log = new PlatformLogger(PlatformLogger.Bridge.convert(
// We pass PlatformLogger.class.getModule() (java.base)
// rather than the actual module of the caller
// because we want PlatformLoggers to be system loggers: we
// won't need to resolve any resource bundles anyway.
// Note: Many unit tests depend on the fact that
// PlatformLogger.getLoggerFromFinder is not caller
// sensitive, and this strategy ensure that the tests
// still pass.
LazyLoggers.getLazyLogger(name, PlatformLogger.class.getModule())));
loggers.put(name, new WeakReference<>(log));
}
return log;
}
// The system loggerProxy returned by LazyLoggers
// This may be a lazy logger - see jdk.internal.logger.LazyLoggers,
// or may be a Logger instance (or a wrapper thereof).
//
private final PlatformLogger.Bridge loggerProxy;
private PlatformLogger(PlatformLogger.Bridge loggerProxy) {
this.loggerProxy = loggerProxy;
}
A convenience method to test if the logger is turned off.
(i.e. its level is OFF).
Returns: whether the logger is turned off.
/**
* A convenience method to test if the logger is turned off.
* (i.e. its level is OFF).
* @return whether the logger is turned off.
*/
public boolean isEnabled() {
return loggerProxy.isEnabled();
}
Gets the name for this platform logger.
Returns: the name of the platform logger.
/**
* Gets the name for this platform logger.
* @return the name of the platform logger.
*/
public String getName() {
return loggerProxy.getName();
}
Returns true if a message of the given level would actually
be logged by this logger.
Params: - level – the level
Returns: whether a message of that level would be logged
/**
* Returns true if a message of the given level would actually
* be logged by this logger.
* @param level the level
* @return whether a message of that level would be logged
*/
public boolean isLoggable(Level level) {
if (level == null) {
throw new NullPointerException();
}
return loggerProxy.isLoggable(level);
}
Get the log level that has been specified for this PlatformLogger.
The result may be null, which means that this logger's
effective level will be inherited from its parent.
Returns: this PlatformLogger's level
/**
* Get the log level that has been specified for this PlatformLogger.
* The result may be null, which means that this logger's
* effective level will be inherited from its parent.
*
* @return this PlatformLogger's level
*/
public Level level() {
final ConfigurableBridge.LoggerConfiguration spi =
PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);
return spi == null ? null : spi.getPlatformLevel();
}
Set the log level specifying which message levels will be logged by this logger. Message levels lower than this value will be discarded. The level value Level.OFF
can be used to turn off logging.
If the new level is null, it means that this node should
inherit its level from its nearest ancestor with a specific
(non-null) level value.
Params: - newLevel – the new value for the log level (may be null)
Deprecated: Platform Loggers should not be configured programmatically. This method will not work if a custom LoggerFinder
is installed.
/**
* Set the log level specifying which message levels will be
* logged by this logger. Message levels lower than this
* value will be discarded. The level value {@link Level#OFF}
* can be used to turn off logging.
* <p>
* If the new level is null, it means that this node should
* inherit its level from its nearest ancestor with a specific
* (non-null) level value.
*
* @param newLevel the new value for the log level (may be null)
* @deprecated Platform Loggers should not be configured programmatically.
* This method will not work if a custom {@link
* java.lang.System.LoggerFinder} is installed.
*/
@Deprecated
public void setLevel(Level newLevel) {
final ConfigurableBridge.LoggerConfiguration spi =
PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);;
if (spi != null) {
spi.setPlatformLevel(newLevel);
}
}
Logs a SEVERE message.
Params: - msg – the message
/**
* Logs a SEVERE message.
* @param msg the message
*/
public void severe(String msg) {
loggerProxy.log(Level.SEVERE, msg, (Object[])null);
}
public void severe(String msg, Throwable t) {
loggerProxy.log(Level.SEVERE, msg, t);
}
public void severe(String msg, Object... params) {
loggerProxy.log(Level.SEVERE, msg, params);
}
Logs a WARNING message.
Params: - msg – the message
/**
* Logs a WARNING message.
* @param msg the message
*/
public void warning(String msg) {
loggerProxy.log(Level.WARNING, msg, (Object[])null);
}
public void warning(String msg, Throwable t) {
loggerProxy.log(Level.WARNING, msg, t);
}
public void warning(String msg, Object... params) {
loggerProxy.log(Level.WARNING, msg, params);
}
Logs an INFO message.
Params: - msg – the message
/**
* Logs an INFO message.
* @param msg the message
*/
public void info(String msg) {
loggerProxy.log(Level.INFO, msg, (Object[])null);
}
public void info(String msg, Throwable t) {
loggerProxy.log(Level.INFO, msg, t);
}
public void info(String msg, Object... params) {
loggerProxy.log(Level.INFO, msg, params);
}
Logs a CONFIG message.
Params: - msg – the message
/**
* Logs a CONFIG message.
* @param msg the message
*/
public void config(String msg) {
loggerProxy.log(Level.CONFIG, msg, (Object[])null);
}
public void config(String msg, Throwable t) {
loggerProxy.log(Level.CONFIG, msg, t);
}
public void config(String msg, Object... params) {
loggerProxy.log(Level.CONFIG, msg, params);
}
Logs a FINE message.
Params: - msg – the message
/**
* Logs a FINE message.
* @param msg the message
*/
public void fine(String msg) {
loggerProxy.log(Level.FINE, msg, (Object[])null);
}
public void fine(String msg, Throwable t) {
loggerProxy.log(Level.FINE, msg, t);
}
public void fine(String msg, Object... params) {
loggerProxy.log(Level.FINE, msg, params);
}
Logs a FINER message.
Params: - msg – the message
/**
* Logs a FINER message.
* @param msg the message
*/
public void finer(String msg) {
loggerProxy.log(Level.FINER, msg, (Object[])null);
}
public void finer(String msg, Throwable t) {
loggerProxy.log(Level.FINER, msg, t);
}
public void finer(String msg, Object... params) {
loggerProxy.log(Level.FINER, msg, params);
}
Logs a FINEST message.
Params: - msg – the message
/**
* Logs a FINEST message.
* @param msg the message
*/
public void finest(String msg) {
loggerProxy.log(Level.FINEST, msg, (Object[])null);
}
public void finest(String msg, Throwable t) {
loggerProxy.log(Level.FINEST, msg, t);
}
public void finest(String msg, Object... params) {
loggerProxy.log(Level.FINEST, msg, params);
}
// ------------------------------------
// Maps used for Level conversion
// ------------------------------------
// This map is indexed by java.util.spi.Logger.Level.ordinal() and returns
// a PlatformLogger.Level
//
// ALL, TRACE, DEBUG, INFO, WARNING, ERROR, OFF
private static final Level[] spi2platformLevelMapping = {
Level.ALL, // mapped from ALL
Level.FINER, // mapped from TRACE
Level.FINE, // mapped from DEBUG
Level.INFO, // mapped from INFO
Level.WARNING, // mapped from WARNING
Level.SEVERE, // mapped from ERROR
Level.OFF // mapped from OFF
};
public static Level toPlatformLevel(java.lang.System.Logger.Level level) {
if (level == null) return null;
assert level.ordinal() < spi2platformLevelMapping.length;
return spi2platformLevelMapping[level.ordinal()];
}
}