mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
516 lines
19 KiB
Java
516 lines
19 KiB
Java
/*
|
|
* 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 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.
|
|
*/
|
|
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.
|
|
* @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.
|
|
*
|
|
*/
|
|
public static interface Bridge {
|
|
|
|
/**
|
|
* 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.
|
|
* @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 {@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.
|
|
* @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).
|
|
* @return whether the logger is turned off.
|
|
*/
|
|
public boolean isEnabled() {
|
|
return loggerProxy.isEnabled();
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* @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.
|
|
*
|
|
* @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 {@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.
|
|
* @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.
|
|
* @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.
|
|
* @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.
|
|
* @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.
|
|
* @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.
|
|
* @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.
|
|
* @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()];
|
|
}
|
|
|
|
}
|