Path: blob/master/src/java.base/share/classes/sun/util/logging/PlatformLogger.java
41159 views
/*1* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package sun.util.logging;2728import java.lang.ref.WeakReference;29import java.util.Arrays;30import java.util.HashMap;31import java.util.Map;32import java.util.ResourceBundle;33import java.util.function.Supplier;34import jdk.internal.logger.LazyLoggers;35import jdk.internal.logger.LoggerWrapper;3637/**38* Platform logger provides an API for the JRE components to log39* messages. This enables the runtime components to eliminate the40* static dependency of the logging facility and also defers the41* java.util.logging initialization until it is enabled.42* In addition, the PlatformLogger API can be used if the logging43* module does not exist.44*45* If the logging facility is not enabled, the platform loggers46* will output log messages per the default logging configuration47* (see below). In this implementation, it does not log48* the stack frame information issuing the log message.49*50* When the logging facility is enabled (at startup or runtime),51* the backend logger will be created for each platform52* logger and all log messages will be forwarded to the Logger53* to handle.54*55* The PlatformLogger uses an underlying PlatformLogger.Bridge instance56* obtained by calling {@link PlatformLogger.Bridge#convert PlatformLogger.Bridge.convert(}57* {@link jdk.internal.logger.LazyLoggers#getLazyLogger(java.lang.String, java.lang.Class)58* jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))}.59*60* Logging facility is "enabled" when one of the following61* conditions is met:62* 1) ServiceLoader.load({@link java.lang.System.LoggerFinder LoggerFinder.class},63* ClassLoader.getSystemClassLoader()).iterator().hasNext().64* 2) ServiceLoader.loadInstalled({@link jdk.internal.logger.DefaultLoggerFinder}).iterator().hasNext(),65* and 2.1) a system property "java.util.logging.config.class" or66* "java.util.logging.config.file" is set67* or 2.2) java.util.logging.LogManager or java.util.logging.Logger68* is referenced that will trigger the logging initialization.69*70* Default logging configuration:71*72* No LoggerFinder service implementation declared73* global logging level = INFO74* handlers = java.util.logging.ConsoleHandler75* java.util.logging.ConsoleHandler.level = INFO76* java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter77*78* Limitation:79* {@code <JAVA_HOME>/conf/logging.properties} is the system-wide logging80* configuration defined in the specification and read in the81* default case to configure any java.util.logging.Logger instances.82* Platform loggers will not detect if {@code <JAVA_HOME>/conf/logging.properties}83* is modified. In other words, unless the java.util.logging API84* is used at runtime or the logging system properties is set,85* the platform loggers will use the default setting described above.86* The platform loggers are designed for JDK developers use and87* this limitation can be workaround with setting88* -Djava.util.logging.config.file system property.89* <br>90* Calling PlatformLogger.setLevel will not work when there is a custom91* LoggerFinder installed - and as a consequence {@link #setLevel setLevel}92* is now deprecated.93*94* @since 1.795*/96public class PlatformLogger {9798/**99* PlatformLogger logging levels.100*/101public static enum Level {102// The name and value must match that of {@code java.util.logging.Level}s.103// Declare in ascending order of the given value for binary search.104ALL(System.Logger.Level.ALL),105FINEST(System.Logger.Level.TRACE),106FINER(System.Logger.Level.TRACE),107FINE(System.Logger.Level.DEBUG),108CONFIG(System.Logger.Level.DEBUG),109INFO(System.Logger.Level.INFO),110WARNING(System.Logger.Level.WARNING),111SEVERE(System.Logger.Level.ERROR),112OFF(System.Logger.Level.OFF);113114final System.Logger.Level systemLevel;115Level(System.Logger.Level systemLevel) {116this.systemLevel = systemLevel;117}118119// The integer values must match that of {@code java.util.logging.Level}120// objects.121private static final int SEVERITY_OFF = Integer.MAX_VALUE;122private static final int SEVERITY_SEVERE = 1000;123private static final int SEVERITY_WARNING = 900;124private static final int SEVERITY_INFO = 800;125private static final int SEVERITY_CONFIG = 700;126private static final int SEVERITY_FINE = 500;127private static final int SEVERITY_FINER = 400;128private static final int SEVERITY_FINEST = 300;129private static final int SEVERITY_ALL = Integer.MIN_VALUE;130131// ascending order for binary search matching the list of enum constants132private static final int[] LEVEL_VALUES = new int[] {133SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,134SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,135SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF136};137138public System.Logger.Level systemLevel() {139return systemLevel;140}141142public int intValue() {143return LEVEL_VALUES[this.ordinal()];144}145146/**147* Maps a severity value to an effective logger level.148* @param level The severity of the messages that should be149* logged with a logger set to the returned level.150* @return The effective logger level, which is the nearest Level value151* whose severity is greater or equal to the given level.152* For level > SEVERE (OFF excluded), return SEVERE.153*/154public static Level valueOf(int level) {155switch (level) {156// ordering per the highest occurrences in the jdk source157// finest, fine, finer, info first158case SEVERITY_FINEST : return Level.FINEST;159case SEVERITY_FINE : return Level.FINE;160case SEVERITY_FINER : return Level.FINER;161case SEVERITY_INFO : return Level.INFO;162case SEVERITY_WARNING : return Level.WARNING;163case SEVERITY_CONFIG : return Level.CONFIG;164case SEVERITY_SEVERE : return Level.SEVERE;165case SEVERITY_OFF : return Level.OFF;166case SEVERITY_ALL : return Level.ALL;167}168// return the nearest Level value >= the given level,169// for level > SEVERE, return SEVERE and exclude OFF170int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);171return values()[i >= 0 ? i : (-i-1)];172}173}174175/**176*177* The PlatformLogger.Bridge interface is implemented by the System.Logger178* objects returned by our default JUL provider - so that JRE classes using179* PlatformLogger see no difference when JUL is the actual backend.180*181* PlatformLogger is now only a thin adaptation layer over the same182* loggers than returned by java.lang.System.getLogger(String name).183*184* The recommendation for JRE classes going forward is to use185* java.lang.System.getLogger(String name), which will186* use Lazy Loggers when possible and necessary.187*188*/189public static interface Bridge {190191/**192* Gets the name for this platform logger.193* @return the name of the platform logger.194*/195public String getName();196197/**198* Returns true if a message of the given level would actually199* be logged by this logger.200* @param level the level201* @return whether a message of that level would be logged202*/203public boolean isLoggable(Level level);204public boolean isEnabled();205206public void log(Level level, String msg);207public void log(Level level, String msg, Throwable thrown);208public void log(Level level, String msg, Object... params);209public void log(Level level, Supplier<String> msgSupplier);210public void log(Level level, Throwable thrown, Supplier<String> msgSupplier);211public void logp(Level level, String sourceClass, String sourceMethod, String msg);212public void logp(Level level, String sourceClass, String sourceMethod,213Supplier<String> msgSupplier);214public void logp(Level level, String sourceClass, String sourceMethod,215String msg, Object... params);216public void logp(Level level, String sourceClass, String sourceMethod,217String msg, Throwable thrown);218public void logp(Level level, String sourceClass, String sourceMethod,219Throwable thrown, Supplier<String> msgSupplier);220public void logrb(Level level, String sourceClass, String sourceMethod,221ResourceBundle bundle, String msg, Object... params);222public void logrb(Level level, String sourceClass, String sourceMethod,223ResourceBundle bundle, String msg, Throwable thrown);224public void logrb(Level level, ResourceBundle bundle, String msg,225Object... params);226public void logrb(Level level, ResourceBundle bundle, String msg,227Throwable thrown);228229230public static Bridge convert(System.Logger logger) {231if (logger instanceof PlatformLogger.Bridge) {232return (Bridge) logger;233} else {234return new LoggerWrapper<>(logger);235}236}237}238239/**240* The {@code PlatformLogger.ConfigurableBridge} interface is used to241* implement the deprecated {@link PlatformLogger#setLevel} method.242*243* PlatformLogger is now only a thin adaptation layer over the same244* loggers than returned by java.lang.System.getLogger(String name).245*246* The recommendation for JRE classes going forward is to use247* java.lang.System.getLogger(String name), which will248* use Lazy Loggers when possible and necessary.249*250*/251public static interface ConfigurableBridge {252253public abstract class LoggerConfiguration {254public abstract Level getPlatformLevel();255public abstract void setPlatformLevel(Level level);256}257258public default LoggerConfiguration getLoggerConfiguration() {259return null;260}261262public static LoggerConfiguration getLoggerConfiguration(PlatformLogger.Bridge logger) {263if (logger instanceof PlatformLogger.ConfigurableBridge) {264return ((ConfigurableBridge) logger).getLoggerConfiguration();265} else {266return null;267}268}269}270271// Table of known loggers. Maps names to PlatformLoggers.272private static final Map<String,WeakReference<PlatformLogger>> loggers =273new HashMap<>();274275/**276* Returns a PlatformLogger of a given name.277* @param name the name of the logger278* @return a PlatformLogger279*/280public static synchronized PlatformLogger getLogger(String name) {281PlatformLogger log = null;282WeakReference<PlatformLogger> ref = loggers.get(name);283if (ref != null) {284log = ref.get();285}286if (log == null) {287log = new PlatformLogger(PlatformLogger.Bridge.convert(288// We pass PlatformLogger.class.getModule() (java.base)289// rather than the actual module of the caller290// because we want PlatformLoggers to be system loggers: we291// won't need to resolve any resource bundles anyway.292// Note: Many unit tests depend on the fact that293// PlatformLogger.getLoggerFromFinder is not caller294// sensitive, and this strategy ensure that the tests295// still pass.296LazyLoggers.getLazyLogger(name, PlatformLogger.class.getModule())));297loggers.put(name, new WeakReference<>(log));298}299return log;300}301302// The system loggerProxy returned by LazyLoggers303// This may be a lazy logger - see jdk.internal.logger.LazyLoggers,304// or may be a Logger instance (or a wrapper thereof).305//306private final PlatformLogger.Bridge loggerProxy;307private PlatformLogger(PlatformLogger.Bridge loggerProxy) {308this.loggerProxy = loggerProxy;309}310311/**312* A convenience method to test if the logger is turned off.313* (i.e. its level is OFF).314* @return whether the logger is turned off.315*/316public boolean isEnabled() {317return loggerProxy.isEnabled();318}319320/**321* Gets the name for this platform logger.322* @return the name of the platform logger.323*/324public String getName() {325return loggerProxy.getName();326}327328/**329* Returns true if a message of the given level would actually330* be logged by this logger.331* @param level the level332* @return whether a message of that level would be logged333*/334public boolean isLoggable(Level level) {335if (level == null) {336throw new NullPointerException();337}338339return loggerProxy.isLoggable(level);340}341342/**343* Get the log level that has been specified for this PlatformLogger.344* The result may be null, which means that this logger's345* effective level will be inherited from its parent.346*347* @return this PlatformLogger's level348*/349public Level level() {350final ConfigurableBridge.LoggerConfiguration spi =351PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);352return spi == null ? null : spi.getPlatformLevel();353}354355/**356* Set the log level specifying which message levels will be357* logged by this logger. Message levels lower than this358* value will be discarded. The level value {@link Level#OFF}359* can be used to turn off logging.360* <p>361* If the new level is null, it means that this node should362* inherit its level from its nearest ancestor with a specific363* (non-null) level value.364*365* @param newLevel the new value for the log level (may be null)366* @deprecated Platform Loggers should not be configured programmatically.367* This method will not work if a custom {@link368* java.lang.System.LoggerFinder} is installed.369*/370@Deprecated371public void setLevel(Level newLevel) {372final ConfigurableBridge.LoggerConfiguration spi =373PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);;374if (spi != null) {375spi.setPlatformLevel(newLevel);376}377}378379/**380* Logs a SEVERE message.381* @param msg the message382*/383public void severe(String msg) {384loggerProxy.log(Level.SEVERE, msg, (Object[])null);385}386387public void severe(String msg, Throwable t) {388loggerProxy.log(Level.SEVERE, msg, t);389}390391public void severe(String msg, Object... params) {392loggerProxy.log(Level.SEVERE, msg, params);393}394395/**396* Logs a WARNING message.397* @param msg the message398*/399public void warning(String msg) {400loggerProxy.log(Level.WARNING, msg, (Object[])null);401}402403public void warning(String msg, Throwable t) {404loggerProxy.log(Level.WARNING, msg, t);405}406407public void warning(String msg, Object... params) {408loggerProxy.log(Level.WARNING, msg, params);409}410411/**412* Logs an INFO message.413* @param msg the message414*/415public void info(String msg) {416loggerProxy.log(Level.INFO, msg, (Object[])null);417}418419public void info(String msg, Throwable t) {420loggerProxy.log(Level.INFO, msg, t);421}422423public void info(String msg, Object... params) {424loggerProxy.log(Level.INFO, msg, params);425}426427/**428* Logs a CONFIG message.429* @param msg the message430*/431public void config(String msg) {432loggerProxy.log(Level.CONFIG, msg, (Object[])null);433}434435public void config(String msg, Throwable t) {436loggerProxy.log(Level.CONFIG, msg, t);437}438439public void config(String msg, Object... params) {440loggerProxy.log(Level.CONFIG, msg, params);441}442443/**444* Logs a FINE message.445* @param msg the message446*/447public void fine(String msg) {448loggerProxy.log(Level.FINE, msg, (Object[])null);449}450451public void fine(String msg, Throwable t) {452loggerProxy.log(Level.FINE, msg, t);453}454455public void fine(String msg, Object... params) {456loggerProxy.log(Level.FINE, msg, params);457}458459/**460* Logs a FINER message.461* @param msg the message462*/463public void finer(String msg) {464loggerProxy.log(Level.FINER, msg, (Object[])null);465}466467public void finer(String msg, Throwable t) {468loggerProxy.log(Level.FINER, msg, t);469}470471public void finer(String msg, Object... params) {472loggerProxy.log(Level.FINER, msg, params);473}474475/**476* Logs a FINEST message.477* @param msg the message478*/479public void finest(String msg) {480loggerProxy.log(Level.FINEST, msg, (Object[])null);481}482483public void finest(String msg, Throwable t) {484loggerProxy.log(Level.FINEST, msg, t);485}486487public void finest(String msg, Object... params) {488loggerProxy.log(Level.FINEST, msg, params);489}490491// ------------------------------------492// Maps used for Level conversion493// ------------------------------------494495// This map is indexed by java.util.spi.Logger.Level.ordinal() and returns496// a PlatformLogger.Level497//498// ALL, TRACE, DEBUG, INFO, WARNING, ERROR, OFF499private static final Level[] spi2platformLevelMapping = {500Level.ALL, // mapped from ALL501Level.FINER, // mapped from TRACE502Level.FINE, // mapped from DEBUG503Level.INFO, // mapped from INFO504Level.WARNING, // mapped from WARNING505Level.SEVERE, // mapped from ERROR506Level.OFF // mapped from OFF507};508509public static Level toPlatformLevel(java.lang.System.Logger.Level level) {510if (level == null) return null;511assert level.ordinal() < spi2platformLevelMapping.length;512return spi2platformLevelMapping[level.ordinal()];513}514515}516517518