1 /*
   2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package sun.util.logging;
  28 
  29 import java.lang.ref.WeakReference;
  30 import java.util.Arrays;
  31 import java.util.HashMap;
  32 import java.util.Map;
  33 import java.util.ResourceBundle;
  34 import java.util.function.Supplier;
  35 import jdk.internal.logger.LazyLoggers;
  36 import jdk.internal.logger.LoggerWrapper;
  37 
  38 /**
  39  * Platform logger provides an API for the JRE components to log
  40  * messages.  This enables the runtime components to eliminate the
  41  * static dependency of the logging facility and also defers the
  42  * java.util.logging initialization until it is enabled.
  43  * In addition, the PlatformLogger API can be used if the logging
  44  * module does not exist.
  45  *
  46  * If the logging facility is not enabled, the platform loggers
  47  * will output log messages per the default logging configuration
  48  * (see below). In this implementation, it does not log the
  49  * the stack frame information issuing the log message.
  50  *
  51  * When the logging facility is enabled (at startup or runtime),
  52  * the backend logger will be created for each platform
  53  * logger and all log messages will be forwarded to the Logger
  54  * to handle.
  55  *
  56  * The PlatformLogger uses an underlying PlatformLogger.Bridge instance
  57  * obtained by calling {@link PlatformLogger.Bridge#convert PlatformLogger.Bridge.convert(}
  58  * {@link jdk.internal.logger.LazyLoggers#getLazyLogger(java.lang.String, java.lang.Class)
  59  * jdk.internal.logger.LazyLoggers#getLazyLogger(name, PlatformLogger.class))}.
  60  *
  61  * Logging facility is "enabled" when one of the following
  62  * conditions is met:
  63  * 1) ServiceLoader.load({@link java.lang.System.LoggerFinder LoggerFinder.class},
  64  *    ClassLoader.getSystemClassLoader()).iterator().hasNext().
  65  * 2) ServiceLoader.loadInstalled({@link jdk.internal.logger.DefaultLoggerFinder}).iterator().hasNext(),
  66  *    and 2.1) a system property "java.util.logging.config.class" or
  67  *             "java.util.logging.config.file" is set
  68  *     or  2.2) java.util.logging.LogManager or java.util.logging.Logger
  69  *              is referenced that will trigger the logging initialization.
  70  *
  71  * Default logging configuration:
  72  *
  73  *   No LoggerFinder service implementation declared
  74  *   global logging level = INFO
  75  *   handlers = java.util.logging.ConsoleHandler
  76  *   java.util.logging.ConsoleHandler.level = INFO
  77  *   java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
  78  *
  79  * Limitation:
  80  * {@code <JAVA_HOME>/conf/logging.properties} is the system-wide logging
  81  * configuration defined in the specification and read in the
  82  * default case to configure any java.util.logging.Logger instances.
  83  * Platform loggers will not detect if {@code <JAVA_HOME>/conf/logging.properties}
  84  * is modified. In other words, unless the java.util.logging API
  85  * is used at runtime or the logging system properties is set,
  86  * the platform loggers will use the default setting described above.
  87  * The platform loggers are designed for JDK developers use and
  88  * this limitation can be workaround with setting
  89  * -Djava.util.logging.config.file system property.
  90  * <br>
  91  * Calling PlatformLogger.setLevel will not work when there is a custom
  92  * LoggerFinder installed - and as a consequence {@link #setLevel setLevel}
  93  * is now deprecated.
  94  *
  95  * @since 1.7
  96  */
  97 public class PlatformLogger {
  98 
  99     /**
 100      * PlatformLogger logging levels.
 101      */
 102     public static enum Level {
 103         // The name and value must match that of {@code java.util.logging.Level}s.
 104         // Declare in ascending order of the given value for binary search.
 105         ALL(System.Logger.Level.ALL),
 106         FINEST(System.Logger.Level.TRACE),
 107         FINER(System.Logger.Level.TRACE),
 108         FINE(System.Logger.Level.DEBUG),
 109         CONFIG(System.Logger.Level.DEBUG),
 110         INFO(System.Logger.Level.INFO),
 111         WARNING(System.Logger.Level.WARNING),
 112         SEVERE(System.Logger.Level.ERROR),
 113         OFF(System.Logger.Level.OFF);
 114 
 115         final System.Logger.Level systemLevel;
 116         Level(System.Logger.Level systemLevel) {
 117             this.systemLevel = systemLevel;
 118         }
 119 
 120         // The integer values must match that of {@code java.util.logging.Level}
 121         // objects.
 122         private static final int SEVERITY_OFF     = Integer.MAX_VALUE;
 123         private static final int SEVERITY_SEVERE  = 1000;
 124         private static final int SEVERITY_WARNING = 900;
 125         private static final int SEVERITY_INFO    = 800;
 126         private static final int SEVERITY_CONFIG  = 700;
 127         private static final int SEVERITY_FINE    = 500;
 128         private static final int SEVERITY_FINER   = 400;
 129         private static final int SEVERITY_FINEST  = 300;
 130         private static final int SEVERITY_ALL     = Integer.MIN_VALUE;
 131 
 132         // ascending order for binary search matching the list of enum constants
 133         private static final int[] LEVEL_VALUES = new int[] {
 134             SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,
 135             SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,
 136             SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF
 137         };
 138 
 139         public System.Logger.Level systemLevel() {
 140             return systemLevel;
 141         }
 142 
 143         public int intValue() {
 144             return LEVEL_VALUES[this.ordinal()];
 145         }
 146 
 147         /**
 148          * Maps a severity value to an effective logger level.
 149          * @param level The severity of the messages that should be
 150          *        logged with a logger set to the returned level.
 151          * @return The effective logger level, which is the nearest Level value
 152          *         whose severity is greater or equal to the given level.
 153          *         For level > SEVERE (OFF excluded), return SEVERE.
 154          */
 155         public static Level valueOf(int level) {
 156             switch (level) {
 157                 // ordering per the highest occurrences in the jdk source
 158                 // finest, fine, finer, info first
 159                 case SEVERITY_FINEST  : return Level.FINEST;
 160                 case SEVERITY_FINE    : return Level.FINE;
 161                 case SEVERITY_FINER   : return Level.FINER;
 162                 case SEVERITY_INFO    : return Level.INFO;
 163                 case SEVERITY_WARNING : return Level.WARNING;
 164                 case SEVERITY_CONFIG  : return Level.CONFIG;
 165                 case SEVERITY_SEVERE  : return Level.SEVERE;
 166                 case SEVERITY_OFF     : return Level.OFF;
 167                 case SEVERITY_ALL     : return Level.ALL;
 168             }
 169             // return the nearest Level value >= the given level,
 170             // for level > SEVERE, return SEVERE and exclude OFF
 171             int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);
 172             return values()[i >= 0 ? i : (-i-1)];
 173         }
 174     }
 175 
 176     /**
 177      *
 178      * The PlatformLogger.Bridge interface is implemented by the System.Logger
 179      * objects returned by our default JUL provider - so that JRE classes using
 180      * PlatformLogger see no difference when JUL is the actual backend.
 181      *
 182      * PlatformLogger is now only a thin adaptation layer over the same
 183      * loggers than returned by java.lang.System.getLogger(String name).
 184      *
 185      * The recommendation for JRE classes going forward is to use
 186      * java.lang.System.getLogger(String name), which will
 187      * use Lazy Loggers when possible and necessary.
 188      *
 189      */
 190     public static interface Bridge {
 191 
 192         /**
 193          * Gets the name for this platform logger.
 194          * @return the name of the platform logger.
 195          */
 196         public String getName();
 197 
 198         /**
 199          * Returns true if a message of the given level would actually
 200          * be logged by this logger.
 201          * @param level the level
 202          * @return whether a message of that level would be logged
 203          */
 204         public boolean isLoggable(Level level);
 205         public boolean isEnabled();
 206 
 207         public void log(Level level, String msg);
 208         public void log(Level level, String msg, Throwable thrown);
 209         public void log(Level level, String msg, Object... params);
 210         public void log(Level level, Supplier<String> msgSupplier);
 211         public void log(Level level, Throwable thrown, Supplier<String> msgSupplier);
 212         public void logp(Level level, String sourceClass, String sourceMethod, String msg);
 213         public void logp(Level level, String sourceClass, String sourceMethod,
 214                          Supplier<String> msgSupplier);
 215         public void logp(Level level, String sourceClass, String sourceMethod,
 216                                                     String msg, Object... params);
 217         public void logp(Level level, String sourceClass, String sourceMethod,
 218                          String msg, Throwable thrown);
 219         public void logp(Level level, String sourceClass, String sourceMethod,
 220                          Throwable thrown, Supplier<String> msgSupplier);
 221         public void logrb(Level level, String sourceClass, String sourceMethod,
 222                           ResourceBundle bundle, String msg, Object... params);
 223         public void logrb(Level level, String sourceClass, String sourceMethod,
 224                           ResourceBundle bundle, String msg, Throwable thrown);
 225         public void logrb(Level level, ResourceBundle bundle, String msg,
 226                 Object... params);
 227         public void logrb(Level level, ResourceBundle bundle, String msg,
 228                 Throwable thrown);
 229 
 230 
 231         public static Bridge convert(System.Logger logger) {
 232             if (logger instanceof PlatformLogger.Bridge) {
 233                 return (Bridge) logger;
 234             } else {
 235                 return new LoggerWrapper<>(logger);
 236             }
 237         }
 238     }
 239 
 240     /**
 241      * The {@code PlatformLogger.ConfigurableBridge} interface is used to
 242      * implement the deprecated {@link PlatformLogger#setLevel} method.
 243      *
 244      * PlatformLogger is now only a thin adaptation layer over the same
 245      * loggers than returned by java.lang.System.getLogger(String name).
 246      *
 247      * The recommendation for JRE classes going forward is to use
 248      * java.lang.System.getLogger(String name), which will
 249      * use Lazy Loggers when possible and necessary.
 250      *
 251      */
 252     public static interface ConfigurableBridge {
 253 
 254         public abstract class LoggerConfiguration {
 255             public abstract Level getPlatformLevel();
 256             public abstract void setPlatformLevel(Level level);
 257         }
 258 
 259         public default LoggerConfiguration getLoggerConfiguration() {
 260             return null;
 261         }
 262 
 263         public static LoggerConfiguration getLoggerConfiguration(PlatformLogger.Bridge logger) {
 264             if (logger instanceof PlatformLogger.ConfigurableBridge) {
 265                 return ((ConfigurableBridge) logger).getLoggerConfiguration();
 266             } else {
 267                 return null;
 268             }
 269         }
 270     }
 271 
 272     // Table of known loggers.  Maps names to PlatformLoggers.
 273     private static final Map<String,WeakReference<PlatformLogger>> loggers =
 274         new HashMap<>();
 275 
 276     /**
 277      * Returns a PlatformLogger of a given name.
 278      * @param name the name of the logger
 279      * @return a PlatformLogger
 280      */
 281     public static synchronized PlatformLogger getLogger(String name) {
 282         PlatformLogger log = null;
 283         WeakReference<PlatformLogger> ref = loggers.get(name);
 284         if (ref != null) {
 285             log = ref.get();
 286         }
 287         if (log == null) {
 288             log = new PlatformLogger(PlatformLogger.Bridge.convert(
 289                     // We pass PlatformLogger.class.getModule() (java.base)
 290                     // rather than the actual module of the caller
 291                     // because we want PlatformLoggers to be system loggers: we
 292                     // won't need to resolve any resource bundles anyway.
 293                     // Note: Many unit tests depend on the fact that
 294                     //       PlatformLogger.getLoggerFromFinder is not caller
 295                     //       sensitive, and this strategy ensure that the tests
 296                     //       still pass.
 297                     LazyLoggers.getLazyLogger(name, PlatformLogger.class.getModule())));
 298             loggers.put(name, new WeakReference<>(log));
 299         }
 300         return log;
 301     }
 302 
 303     // The system loggerProxy returned by LazyLoggers
 304     // This may be a lazy logger - see jdk.internal.logger.LazyLoggers,
 305     // or may be a Logger instance (or a wrapper thereof).
 306     //
 307     private final PlatformLogger.Bridge loggerProxy;
 308     private PlatformLogger(PlatformLogger.Bridge loggerProxy) {
 309         this.loggerProxy = loggerProxy;
 310     }
 311 
 312     /**
 313      * A convenience method to test if the logger is turned off.
 314      * (i.e. its level is OFF).
 315      * @return whether the logger is turned off.
 316      */
 317     public boolean isEnabled() {
 318         return loggerProxy.isEnabled();
 319     }
 320 
 321     /**
 322      * Gets the name for this platform logger.
 323      * @return the name of the platform logger.
 324      */
 325     public String getName() {
 326         return loggerProxy.getName();
 327     }
 328 
 329     /**
 330      * Returns true if a message of the given level would actually
 331      * be logged by this logger.
 332      * @param level the level
 333      * @return whether a message of that level would be logged
 334      */
 335     public boolean isLoggable(Level level) {
 336         if (level == null) {
 337             throw new NullPointerException();
 338         }
 339 
 340         return loggerProxy.isLoggable(level);
 341     }
 342 
 343     /**
 344      * Get the log level that has been specified for this PlatformLogger.
 345      * The result may be null, which means that this logger's
 346      * effective level will be inherited from its parent.
 347      *
 348      * @return  this PlatformLogger's level
 349      */
 350     public Level level() {
 351         final ConfigurableBridge.LoggerConfiguration spi =
 352                 PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);
 353         return spi == null ? null : spi.getPlatformLevel();
 354     }
 355 
 356     /**
 357      * Set the log level specifying which message levels will be
 358      * logged by this logger.  Message levels lower than this
 359      * value will be discarded.  The level value {@link Level#OFF}
 360      * can be used to turn off logging.
 361      * <p>
 362      * If the new level is null, it means that this node should
 363      * inherit its level from its nearest ancestor with a specific
 364      * (non-null) level value.
 365      *
 366      * @param newLevel the new value for the log level (may be null)
 367      * @deprecated Platform Loggers should not be configured programmatically.
 368      *             This method will not work if a custom {@link
 369      *             java.lang.System.LoggerFinder} is installed.
 370      */
 371     @Deprecated
 372     public void setLevel(Level newLevel) {
 373         final ConfigurableBridge.LoggerConfiguration spi =
 374                 PlatformLogger.ConfigurableBridge.getLoggerConfiguration(loggerProxy);;
 375         if (spi != null) {
 376             spi.setPlatformLevel(newLevel);
 377         }
 378     }
 379 
 380     /**
 381      * Logs a SEVERE message.
 382      * @param msg the message
 383      */
 384     public void severe(String msg) {
 385         loggerProxy.log(Level.SEVERE, msg, (Object[])null);
 386     }
 387 
 388     public void severe(String msg, Throwable t) {
 389         loggerProxy.log(Level.SEVERE, msg, t);
 390     }
 391 
 392     public void severe(String msg, Object... params) {
 393         loggerProxy.log(Level.SEVERE, msg, params);
 394     }
 395 
 396     /**
 397      * Logs a WARNING message.
 398      * @param msg the message
 399      */
 400     public void warning(String msg) {
 401         loggerProxy.log(Level.WARNING, msg, (Object[])null);
 402     }
 403 
 404     public void warning(String msg, Throwable t) {
 405         loggerProxy.log(Level.WARNING, msg, t);
 406     }
 407 
 408     public void warning(String msg, Object... params) {
 409         loggerProxy.log(Level.WARNING, msg, params);
 410     }
 411 
 412     /**
 413      * Logs an INFO message.
 414      * @param msg the message
 415      */
 416     public void info(String msg) {
 417         loggerProxy.log(Level.INFO, msg, (Object[])null);
 418     }
 419 
 420     public void info(String msg, Throwable t) {
 421         loggerProxy.log(Level.INFO, msg, t);
 422     }
 423 
 424     public void info(String msg, Object... params) {
 425         loggerProxy.log(Level.INFO, msg, params);
 426     }
 427 
 428     /**
 429      * Logs a CONFIG message.
 430      * @param msg the message
 431      */
 432     public void config(String msg) {
 433         loggerProxy.log(Level.CONFIG, msg, (Object[])null);
 434     }
 435 
 436     public void config(String msg, Throwable t) {
 437         loggerProxy.log(Level.CONFIG, msg, t);
 438     }
 439 
 440     public void config(String msg, Object... params) {
 441         loggerProxy.log(Level.CONFIG, msg, params);
 442     }
 443 
 444     /**
 445      * Logs a FINE message.
 446      * @param msg the message
 447      */
 448     public void fine(String msg) {
 449         loggerProxy.log(Level.FINE, msg, (Object[])null);
 450     }
 451 
 452     public void fine(String msg, Throwable t) {
 453         loggerProxy.log(Level.FINE, msg, t);
 454     }
 455 
 456     public void fine(String msg, Object... params) {
 457         loggerProxy.log(Level.FINE, msg, params);
 458     }
 459 
 460     /**
 461      * Logs a FINER message.
 462      * @param msg the message
 463      */
 464     public void finer(String msg) {
 465         loggerProxy.log(Level.FINER, msg, (Object[])null);
 466     }
 467 
 468     public void finer(String msg, Throwable t) {
 469         loggerProxy.log(Level.FINER, msg, t);
 470     }
 471 
 472     public void finer(String msg, Object... params) {
 473         loggerProxy.log(Level.FINER, msg, params);
 474     }
 475 
 476     /**
 477      * Logs a FINEST message.
 478      * @param msg the message
 479      */
 480     public void finest(String msg) {
 481         loggerProxy.log(Level.FINEST, msg, (Object[])null);
 482     }
 483 
 484     public void finest(String msg, Throwable t) {
 485         loggerProxy.log(Level.FINEST, msg, t);
 486     }
 487 
 488     public void finest(String msg, Object... params) {
 489         loggerProxy.log(Level.FINEST, msg, params);
 490     }
 491 
 492     // ------------------------------------
 493     // Maps used for Level conversion
 494     // ------------------------------------
 495 
 496     // This map is indexed by java.util.spi.Logger.Level.ordinal() and returns
 497     // a PlatformLogger.Level
 498     //
 499     // ALL, TRACE, DEBUG, INFO, WARNING, ERROR, OFF
 500     private static final Level[] spi2platformLevelMapping = {
 501             Level.ALL,     // mapped from ALL
 502             Level.FINER,   // mapped from TRACE
 503             Level.FINE,    // mapped from DEBUG
 504             Level.INFO,    // mapped from INFO
 505             Level.WARNING, // mapped from WARNING
 506             Level.SEVERE,  // mapped from ERROR
 507             Level.OFF      // mapped from OFF
 508     };
 509 
 510     public static Level toPlatformLevel(java.lang.System.Logger.Level level) {
 511         if (level == null) return null;
 512         assert level.ordinal() < spi2platformLevelMapping.length;
 513         return spi2platformLevelMapping[level.ordinal()];
 514     }
 515 
 516 }