/* |
|
* 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()]; |
|
} |
|
} |