Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/util/logging/PlatformLogger.java
38918 views
/*1* Copyright (c) 2009, 2013, 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.io.PrintStream;30import java.io.PrintWriter;31import java.io.StringWriter;32import java.security.AccessController;33import java.security.PrivilegedAction;34import java.util.Arrays;35import java.util.Date;36import java.util.HashMap;37import java.util.Map;38import sun.misc.JavaLangAccess;39import sun.misc.SharedSecrets;4041/**42* Platform logger provides an API for the JRE components to log43* messages. This enables the runtime components to eliminate the44* static dependency of the logging facility and also defers the45* java.util.logging initialization until it is enabled.46* In addition, the PlatformLogger API can be used if the logging47* module does not exist.48*49* If the logging facility is not enabled, the platform loggers50* will output log messages per the default logging configuration51* (see below). In this implementation, it does not log the52* the stack frame information issuing the log message.53*54* When the logging facility is enabled (at startup or runtime),55* the java.util.logging.Logger will be created for each platform56* logger and all log messages will be forwarded to the Logger57* to handle.58*59* Logging facility is "enabled" when one of the following60* conditions is met:61* 1) a system property "java.util.logging.config.class" or62* "java.util.logging.config.file" is set63* 2) java.util.logging.LogManager or java.util.logging.Logger64* is referenced that will trigger the logging initialization.65*66* Default logging configuration:67* global logging level = INFO68* handlers = java.util.logging.ConsoleHandler69* java.util.logging.ConsoleHandler.level = INFO70* java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter71*72* Limitation:73* <JAVA_HOME>/lib/logging.properties is the system-wide logging74* configuration defined in the specification and read in the75* default case to configure any java.util.logging.Logger instances.76* Platform loggers will not detect if <JAVA_HOME>/lib/logging.properties77* is modified. In other words, unless the java.util.logging API78* is used at runtime or the logging system properties is set,79* the platform loggers will use the default setting described above.80* The platform loggers are designed for JDK developers use and81* this limitation can be workaround with setting82* -Djava.util.logging.config.file system property.83*84* @since 1.785*/86public class PlatformLogger {8788// The integer values must match that of {@code java.util.logging.Level}89// objects.90private static final int OFF = Integer.MAX_VALUE;91private static final int SEVERE = 1000;92private static final int WARNING = 900;93private static final int INFO = 800;94private static final int CONFIG = 700;95private static final int FINE = 500;96private static final int FINER = 400;97private static final int FINEST = 300;98private static final int ALL = Integer.MIN_VALUE;99100/**101* PlatformLogger logging levels.102*/103public static enum Level {104// The name and value must match that of {@code java.util.logging.Level}s.105// Declare in ascending order of the given value for binary search.106ALL,107FINEST,108FINER,109FINE,110CONFIG,111INFO,112WARNING,113SEVERE,114OFF;115116/**117* Associated java.util.logging.Level lazily initialized in118* JavaLoggerProxy's static initializer only once119* when java.util.logging is available and enabled.120* Only accessed by JavaLoggerProxy.121*/122/* java.util.logging.Level */ Object javaLevel;123124// ascending order for binary search matching the list of enum constants125private static final int[] LEVEL_VALUES = new int[] {126PlatformLogger.ALL, PlatformLogger.FINEST, PlatformLogger.FINER,127PlatformLogger.FINE, PlatformLogger.CONFIG, PlatformLogger.INFO,128PlatformLogger.WARNING, PlatformLogger.SEVERE, PlatformLogger.OFF129};130131public int intValue() {132return LEVEL_VALUES[this.ordinal()];133}134135static Level valueOf(int level) {136switch (level) {137// ordering per the highest occurrences in the jdk source138// finest, fine, finer, info first139case PlatformLogger.FINEST : return Level.FINEST;140case PlatformLogger.FINE : return Level.FINE;141case PlatformLogger.FINER : return Level.FINER;142case PlatformLogger.INFO : return Level.INFO;143case PlatformLogger.WARNING : return Level.WARNING;144case PlatformLogger.CONFIG : return Level.CONFIG;145case PlatformLogger.SEVERE : return Level.SEVERE;146case PlatformLogger.OFF : return Level.OFF;147case PlatformLogger.ALL : return Level.ALL;148}149// return the nearest Level value >= the given level,150// for level > SEVERE, return SEVERE and exclude OFF151int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);152return values()[i >= 0 ? i : (-i-1)];153}154}155156private static final Level DEFAULT_LEVEL = Level.INFO;157private static boolean loggingEnabled;158static {159loggingEnabled = AccessController.doPrivileged(160new PrivilegedAction<Boolean>() {161public Boolean run() {162String cname = System.getProperty("java.util.logging.config.class");163String fname = System.getProperty("java.util.logging.config.file");164return (cname != null || fname != null);165}166});167168// force loading of all JavaLoggerProxy (sub)classes to make JIT de-optimizations169// less probable. Don't initialize JavaLoggerProxy class since170// java.util.logging may not be enabled.171try {172Class.forName("sun.util.logging.PlatformLogger$DefaultLoggerProxy",173false,174PlatformLogger.class.getClassLoader());175Class.forName("sun.util.logging.PlatformLogger$JavaLoggerProxy",176false, // do not invoke class initializer177PlatformLogger.class.getClassLoader());178} catch (ClassNotFoundException ex) {179throw new InternalError(ex);180}181}182183// Table of known loggers. Maps names to PlatformLoggers.184private static Map<String,WeakReference<PlatformLogger>> loggers =185new HashMap<>();186187/**188* Returns a PlatformLogger of a given name.189*/190public static synchronized PlatformLogger getLogger(String name) {191PlatformLogger log = null;192WeakReference<PlatformLogger> ref = loggers.get(name);193if (ref != null) {194log = ref.get();195}196if (log == null) {197log = new PlatformLogger(name);198loggers.put(name, new WeakReference<>(log));199}200return log;201}202203/**204* Initialize java.util.logging.Logger objects for all platform loggers.205* This method is called from LogManager.readPrimordialConfiguration().206*/207public static synchronized void redirectPlatformLoggers() {208if (loggingEnabled || !LoggingSupport.isAvailable()) return;209210loggingEnabled = true;211for (Map.Entry<String, WeakReference<PlatformLogger>> entry : loggers.entrySet()) {212WeakReference<PlatformLogger> ref = entry.getValue();213PlatformLogger plog = ref.get();214if (plog != null) {215plog.redirectToJavaLoggerProxy();216}217}218}219220/**221* Creates a new JavaLoggerProxy and redirects the platform logger to it222*/223private void redirectToJavaLoggerProxy() {224DefaultLoggerProxy lp = DefaultLoggerProxy.class.cast(this.loggerProxy);225JavaLoggerProxy jlp = new JavaLoggerProxy(lp.name, lp.level);226// the order of assignments is important227this.javaLoggerProxy = jlp; // isLoggable checks javaLoggerProxy if set228this.loggerProxy = jlp;229}230231// DefaultLoggerProxy may be replaced with a JavaLoggerProxy object232// when the java.util.logging facility is enabled233private volatile LoggerProxy loggerProxy;234// javaLoggerProxy is only set when the java.util.logging facility is enabled235private volatile JavaLoggerProxy javaLoggerProxy;236private PlatformLogger(String name) {237if (loggingEnabled) {238this.loggerProxy = this.javaLoggerProxy = new JavaLoggerProxy(name);239} else {240this.loggerProxy = new DefaultLoggerProxy(name);241}242}243244/**245* A convenience method to test if the logger is turned off.246* (i.e. its level is OFF).247*/248public boolean isEnabled() {249return loggerProxy.isEnabled();250}251252/**253* Gets the name for this platform logger.254*/255public String getName() {256return loggerProxy.name;257}258259/**260* Returns true if a message of the given level would actually261* be logged by this logger.262*/263public boolean isLoggable(Level level) {264if (level == null) {265throw new NullPointerException();266}267// performance-sensitive method: use two monomorphic call-sites268JavaLoggerProxy jlp = javaLoggerProxy;269return jlp != null ? jlp.isLoggable(level) : loggerProxy.isLoggable(level);270}271272/**273* Get the log level that has been specified for this PlatformLogger.274* The result may be null, which means that this logger's275* effective level will be inherited from its parent.276*277* @return this PlatformLogger's level278*/279public Level level() {280return loggerProxy.getLevel();281}282283/**284* Set the log level specifying which message levels will be285* logged by this logger. Message levels lower than this286* value will be discarded. The level value {@link #OFF}287* can be used to turn off logging.288* <p>289* If the new level is null, it means that this node should290* inherit its level from its nearest ancestor with a specific291* (non-null) level value.292*293* @param newLevel the new value for the log level (may be null)294*/295public void setLevel(Level newLevel) {296loggerProxy.setLevel(newLevel);297}298299/**300* Logs a SEVERE message.301*/302public void severe(String msg) {303loggerProxy.doLog(Level.SEVERE, msg);304}305306public void severe(String msg, Throwable t) {307loggerProxy.doLog(Level.SEVERE, msg, t);308}309310public void severe(String msg, Object... params) {311loggerProxy.doLog(Level.SEVERE, msg, params);312}313314/**315* Logs a WARNING message.316*/317public void warning(String msg) {318loggerProxy.doLog(Level.WARNING, msg);319}320321public void warning(String msg, Throwable t) {322loggerProxy.doLog(Level.WARNING, msg, t);323}324325public void warning(String msg, Object... params) {326loggerProxy.doLog(Level.WARNING, msg, params);327}328329/**330* Logs an INFO message.331*/332public void info(String msg) {333loggerProxy.doLog(Level.INFO, msg);334}335336public void info(String msg, Throwable t) {337loggerProxy.doLog(Level.INFO, msg, t);338}339340public void info(String msg, Object... params) {341loggerProxy.doLog(Level.INFO, msg, params);342}343344/**345* Logs a CONFIG message.346*/347public void config(String msg) {348loggerProxy.doLog(Level.CONFIG, msg);349}350351public void config(String msg, Throwable t) {352loggerProxy.doLog(Level.CONFIG, msg, t);353}354355public void config(String msg, Object... params) {356loggerProxy.doLog(Level.CONFIG, msg, params);357}358359/**360* Logs a FINE message.361*/362public void fine(String msg) {363loggerProxy.doLog(Level.FINE, msg);364}365366public void fine(String msg, Throwable t) {367loggerProxy.doLog(Level.FINE, msg, t);368}369370public void fine(String msg, Object... params) {371loggerProxy.doLog(Level.FINE, msg, params);372}373374/**375* Logs a FINER message.376*/377public void finer(String msg) {378loggerProxy.doLog(Level.FINER, msg);379}380381public void finer(String msg, Throwable t) {382loggerProxy.doLog(Level.FINER, msg, t);383}384385public void finer(String msg, Object... params) {386loggerProxy.doLog(Level.FINER, msg, params);387}388389/**390* Logs a FINEST message.391*/392public void finest(String msg) {393loggerProxy.doLog(Level.FINEST, msg);394}395396public void finest(String msg, Throwable t) {397loggerProxy.doLog(Level.FINEST, msg, t);398}399400public void finest(String msg, Object... params) {401loggerProxy.doLog(Level.FINEST, msg, params);402}403404/**405* Abstract base class for logging support, defining the API and common field.406*/407private static abstract class LoggerProxy {408final String name;409410protected LoggerProxy(String name) {411this.name = name;412}413414abstract boolean isEnabled();415416abstract Level getLevel();417abstract void setLevel(Level newLevel);418419abstract void doLog(Level level, String msg);420abstract void doLog(Level level, String msg, Throwable thrown);421abstract void doLog(Level level, String msg, Object... params);422423abstract boolean isLoggable(Level level);424}425426427private static final class DefaultLoggerProxy extends LoggerProxy {428/**429* Default platform logging support - output messages to System.err -430* equivalent to ConsoleHandler with SimpleFormatter.431*/432private static PrintStream outputStream() {433return System.err;434}435436volatile Level effectiveLevel; // effective level (never null)437volatile Level level; // current level set for this node (may be null)438439DefaultLoggerProxy(String name) {440super(name);441this.effectiveLevel = deriveEffectiveLevel(null);442this.level = null;443}444445boolean isEnabled() {446return effectiveLevel != Level.OFF;447}448449Level getLevel() {450return level;451}452453void setLevel(Level newLevel) {454Level oldLevel = level;455if (oldLevel != newLevel) {456level = newLevel;457effectiveLevel = deriveEffectiveLevel(newLevel);458}459}460461void doLog(Level level, String msg) {462if (isLoggable(level)) {463outputStream().print(format(level, msg, null));464}465}466467void doLog(Level level, String msg, Throwable thrown) {468if (isLoggable(level)) {469outputStream().print(format(level, msg, thrown));470}471}472473void doLog(Level level, String msg, Object... params) {474if (isLoggable(level)) {475String newMsg = formatMessage(msg, params);476outputStream().print(format(level, newMsg, null));477}478}479480boolean isLoggable(Level level) {481Level effectiveLevel = this.effectiveLevel;482return level.intValue() >= effectiveLevel.intValue() && effectiveLevel != Level.OFF;483}484485// derive effective level (could do inheritance search like j.u.l.Logger)486private Level deriveEffectiveLevel(Level level) {487return level == null ? DEFAULT_LEVEL : level;488}489490// Copied from java.util.logging.Formatter.formatMessage491private String formatMessage(String format, Object... parameters) {492// Do the formatting.493try {494if (parameters == null || parameters.length == 0) {495// No parameters. Just return format string.496return format;497}498// Is it a java.text style format?499// Ideally we could match with500// Pattern.compile("\\{\\d").matcher(format).find())501// However the cost is 14% higher, so we cheaply check for502// 1 of the first 4 parameters503if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||504format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {505return java.text.MessageFormat.format(format, parameters);506}507return format;508} catch (Exception ex) {509// Formatting failed: use format string.510return format;511}512}513514private static final String formatString =515LoggingSupport.getSimpleFormat(false); // don't check logging.properties516517// minimize memory allocation518private Date date = new Date();519private synchronized String format(Level level, String msg, Throwable thrown) {520date.setTime(System.currentTimeMillis());521String throwable = "";522if (thrown != null) {523StringWriter sw = new StringWriter();524PrintWriter pw = new PrintWriter(sw);525pw.println();526thrown.printStackTrace(pw);527pw.close();528throwable = sw.toString();529}530531return String.format(formatString,532date,533getCallerInfo(),534name,535level.name(),536msg,537throwable);538}539540// Returns the caller's class and method's name; best effort541// if cannot infer, return the logger's name.542private String getCallerInfo() {543String sourceClassName = null;544String sourceMethodName = null;545546JavaLangAccess access = SharedSecrets.getJavaLangAccess();547Throwable throwable = new Throwable();548int depth = access.getStackTraceDepth(throwable);549550String logClassName = "sun.util.logging.PlatformLogger";551boolean lookingForLogger = true;552for (int ix = 0; ix < depth; ix++) {553// Calling getStackTraceElement directly prevents the VM554// from paying the cost of building the entire stack frame.555StackTraceElement frame =556access.getStackTraceElement(throwable, ix);557String cname = frame.getClassName();558if (lookingForLogger) {559// Skip all frames until we have found the first logger frame.560if (cname.equals(logClassName)) {561lookingForLogger = false;562}563} else {564if (!cname.equals(logClassName)) {565// We've found the relevant frame.566sourceClassName = cname;567sourceMethodName = frame.getMethodName();568break;569}570}571}572573if (sourceClassName != null) {574return sourceClassName + " " + sourceMethodName;575} else {576return name;577}578}579}580581/**582* JavaLoggerProxy forwards all the calls to its corresponding583* java.util.logging.Logger object.584*/585private static final class JavaLoggerProxy extends LoggerProxy {586// initialize javaLevel fields for mapping from Level enum -> j.u.l.Level object587static {588for (Level level : Level.values()) {589level.javaLevel = LoggingSupport.parseLevel(level.name());590}591}592593private final /* java.util.logging.Logger */ Object javaLogger;594595JavaLoggerProxy(String name) {596this(name, null);597}598599JavaLoggerProxy(String name, Level level) {600super(name);601this.javaLogger = LoggingSupport.getLogger(name);602if (level != null) {603// level has been updated and so set the Logger's level604LoggingSupport.setLevel(javaLogger, level.javaLevel);605}606}607608void doLog(Level level, String msg) {609LoggingSupport.log(javaLogger, level.javaLevel, msg);610}611612void doLog(Level level, String msg, Throwable t) {613LoggingSupport.log(javaLogger, level.javaLevel, msg, t);614}615616void doLog(Level level, String msg, Object... params) {617if (!isLoggable(level)) {618return;619}620// only pass String objects to the j.u.l.Logger which may621// be created by untrusted code622int len = (params != null) ? params.length : 0;623Object[] sparams = new String[len];624for (int i = 0; i < len; i++) {625sparams [i] = String.valueOf(params[i]);626}627LoggingSupport.log(javaLogger, level.javaLevel, msg, sparams);628}629630boolean isEnabled() {631return LoggingSupport.isLoggable(javaLogger, Level.OFF.javaLevel);632}633634/**635* Returns the PlatformLogger.Level mapped from j.u.l.Level636* set in the logger. If the j.u.l.Logger is set to a custom Level,637* this method will return the nearest Level.638*/639Level getLevel() {640Object javaLevel = LoggingSupport.getLevel(javaLogger);641if (javaLevel == null) return null;642643try {644return Level.valueOf(LoggingSupport.getLevelName(javaLevel));645} catch (IllegalArgumentException e) {646return Level.valueOf(LoggingSupport.getLevelValue(javaLevel));647}648}649650void setLevel(Level level) {651LoggingSupport.setLevel(javaLogger, level == null ? null : level.javaLevel);652}653654boolean isLoggable(Level level) {655return LoggingSupport.isLoggable(javaLogger, level.javaLevel);656}657}658}659660661