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 }