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 package jdk.internal.logger; 27 28 import java.security.AccessController; 29 import java.security.PrivilegedAction; 30 import java.util.function.BiFunction; 31 import java.lang.System.LoggerFinder; 32 import java.lang.System.Logger; 33 import java.lang.ref.WeakReference; 34 import java.util.Objects; 35 import jdk.internal.misc.VM; 36 import sun.util.logging.PlatformLogger; 37 38 /** 39 * This class is a factory for Lazy Loggers; only system loggers can be 40 * Lazy Loggers. 41 */ 42 public final class LazyLoggers { 43 44 static final RuntimePermission LOGGERFINDER_PERMISSION = 45 new RuntimePermission("loggerFinder"); 46 47 private LazyLoggers() { 48 throw new InternalError(); 49 } 50 51 /** 52 * This class is used to hold the factories that a Lazy Logger will use 53 * to create (or map) its wrapped logger. 54 * @param <L> {@link Logger} or a subclass of {@link Logger}. 55 */ 56 private static final class LazyLoggerFactories<L extends Logger> { 57 58 /** 59 * A factory method to create an SPI logger. 60 * Usually, this will be something like LazyLoggers::getSystemLogger. 61 */ 62 final BiFunction<String, Class<?>, L> loggerSupplier; 63 64 65 public LazyLoggerFactories(BiFunction<String, Class<?>, L> loggerSupplier) { 66 this(Objects.requireNonNull(loggerSupplier), 67 (Void)null); 68 } 69 70 private LazyLoggerFactories(BiFunction<String, Class<?>, L> loggerSupplier, 71 Void unused) { 72 this.loggerSupplier = loggerSupplier; 73 } 74 75 } 76 77 static interface LoggerAccessor { 78 /** 79 * The logger name. 80 * @return The name of the logger that is / will be lazily created. 81 */ 82 public String getLoggerName(); 83 84 /** 85 * Returns the wrapped logger object. 86 * @return the wrapped logger object. 87 */ 88 public Logger wrapped(); 89 90 /** 91 * A PlatformLogger.Bridge view of the wrapped logger object. 92 * @return A PlatformLogger.Bridge view of the wrapped logger object. 93 */ 94 public PlatformLogger.Bridge platform(); 95 } 96 97 /** 98 * The LazyLoggerAccessor class holds all the logic that delays the creation 99 * of the SPI logger until such a time that the VM is booted and the logger 100 * is actually used for logging. 101 * 102 * This class uses the services of the BootstrapLogger class to instantiate 103 * temporary loggers if appropriate. 104 */ 105 static final class LazyLoggerAccessor implements LoggerAccessor { 106 107 // The factories that will be used to create the logger lazyly 108 final LazyLoggerFactories<? extends Logger> factories; 109 110 // We need to pass the actual caller when creating the logger. 111 private final WeakReference<Class<?>> callerRef; 112 113 // The name of the logger that will be created lazyly 114 final String name; 115 // The plain logger SPI object - null until it is accessed for the 116 // first time. 117 private volatile Logger w; 118 // A PlatformLogger.Bridge view of w. 119 private volatile PlatformLogger.Bridge p; 120 121 122 private LazyLoggerAccessor(String name, 123 LazyLoggerFactories<? extends Logger> factories, 124 Class<?> caller) { 125 this(Objects.requireNonNull(name), Objects.requireNonNull(factories), 126 Objects.requireNonNull(caller), null); 127 } 128 129 private LazyLoggerAccessor(String name, 130 LazyLoggerFactories<? extends Logger> factories, 131 Class<?> caller, Void unused) { 132 this.name = name; 133 this.factories = factories; 134 this.callerRef = new WeakReference<Class<?>>(caller); 135 } 136 137 /** 138 * The logger name. 139 * @return The name of the logger that is / will be lazily created. 140 */ 141 @Override 142 public String getLoggerName() { 143 return name; 144 } 145 146 // must be called in synchronized block 147 // set wrapped logger if not set 148 private void setWrappedIfNotSet(Logger wrapped) { 149 if (w == null) { 150 w = wrapped; 151 } 152 } 153 154 /** 253 if (this.w == bootstrap) { 254 this.w = null; this.p = null; 255 } 256 } 257 return this.wrapped(); 258 } 259 260 PlatformLogger.Bridge getConcretePlatformLogger(BootstrapLogger bootstrap) { 261 assert VM.isBooted(); 262 synchronized(this) { 263 // another thread may have already invoked flush() 264 if (this.w == bootstrap) { 265 this.w = null; this.p = null; 266 } 267 } 268 return this.platform(); 269 } 270 271 // Creates the wrapped logger by invoking the SPI. 272 Logger createLogger() { 273 final Class<?> caller = callerRef.get(); 274 if (caller == null) { 275 throw new IllegalStateException("The class for which this logger" 276 + " was created has been garbage collected"); 277 } 278 return this.factories.loggerSupplier.apply(name, caller); 279 } 280 281 /** 282 * Creates a new lazy logger accessor for the named logger. The given 283 * factories will be use when it becomes necessary to actually create 284 * the logger. 285 * @param <T> An interface that extends {@link Logger}. 286 * @param name The logger name. 287 * @param factories The factories that should be used to create the 288 * wrapped logger. 289 * @return A new LazyLoggerAccessor. 290 */ 291 public static LazyLoggerAccessor makeAccessor(String name, 292 LazyLoggerFactories<? extends Logger> factories, Class<?> caller) { 293 return new LazyLoggerAccessor(name, factories, caller); 294 } 295 296 } 297 298 /** 299 * An implementation of {@link Logger} that redirects all calls to a wrapped 300 * instance of {@code Logger}. 301 */ 302 private static class LazyLoggerWrapper 303 extends AbstractLoggerWrapper<Logger> { 304 305 final LoggerAccessor loggerAccessor; 306 307 public LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier) { 308 this(Objects.requireNonNull(loggerSinkSupplier), (Void)null); 309 } 310 311 private LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier, 312 Void unused) { 313 this.loggerAccessor = loggerSinkSupplier; 329 private static volatile LoggerFinder provider; 330 private static LoggerFinder accessLoggerFinder() { 331 LoggerFinder prov = provider; 332 if (prov == null) { 333 // no need to lock: it doesn't matter if we call 334 // getLoggerFinder() twice - since LoggerFinder already caches 335 // the result. 336 // This is just an optimization to avoid the cost of calling 337 // doPrivileged every time. 338 final SecurityManager sm = System.getSecurityManager(); 339 prov = sm == null ? LoggerFinder.getLoggerFinder() : 340 AccessController.doPrivileged( 341 (PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder); 342 provider = prov; 343 } 344 return prov; 345 } 346 347 // Avoid using lambda here as lazy loggers could be created early 348 // in the bootstrap sequence... 349 private static final BiFunction<String, Class<?>, Logger> loggerSupplier = 350 new BiFunction<>() { 351 @Override 352 public Logger apply(String name, Class<?> caller) { 353 return LazyLoggers.getLoggerFromFinder(name, caller); 354 } 355 }; 356 357 private static final LazyLoggerFactories<Logger> factories = 358 new LazyLoggerFactories<>(loggerSupplier); 359 360 361 362 // A concrete implementation of Logger that delegates to a System.Logger, 363 // but only creates the System.Logger instance lazily when it's used for 364 // the first time. 365 // The JdkLazyLogger uses a LazyLoggerAccessor objects, which relies 366 // on the logic embedded in BootstrapLogger to avoid loading the concrete 367 // logger provider until the VM has finished booting. 368 // 369 private static final class JdkLazyLogger extends LazyLoggerWrapper { 370 JdkLazyLogger(String name, Class<?> caller) { 371 this(LazyLoggerAccessor.makeAccessor(name, factories, caller), 372 (Void)null); 373 } 374 private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { 375 super(holder); 376 } 377 } 378 379 /** 380 * Gets a logger from the LoggerFinder. Creates the actual concrete 381 * logger. 382 * @param name name of the logger 383 * @param caller class on behalf of which the logger is created 384 * @return The logger returned by the LoggerFinder. 385 */ 386 static Logger getLoggerFromFinder(String name, Class<?> caller) { 387 final SecurityManager sm = System.getSecurityManager(); 388 if (sm == null) { 389 return accessLoggerFinder().getLogger(name, caller); 390 } else { 391 return AccessController.doPrivileged((PrivilegedAction<Logger>) 392 () -> {return accessLoggerFinder().getLogger(name, caller);}, 393 null, LOGGERFINDER_PERMISSION); 394 } 395 } 396 397 /** 398 * Returns a (possibly lazy) Logger for the caller. 399 * 400 * @param name the logger name 401 * @param caller The class on behalf of which the logger is created. 402 * If the caller is not loaded from the Boot ClassLoader, 403 * the LoggerFinder is accessed and the logger returned 404 * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Class)} 405 * is returned to the caller directly. 406 * Otherwise, the logger returned by 407 * {@link #getLazyLogger(java.lang.String, java.lang.Class)} 408 * is returned to the caller. 409 * 410 * @return a (possibly lazy) Logger instance. 411 */ 412 public static final Logger getLogger(String name, Class<?> caller) { 413 if (caller.getClassLoader() == null) { 414 return getLazyLogger(name, caller); 415 } else { 416 return getLoggerFromFinder(name, caller); 417 } 418 } 419 420 /** 421 * Returns a (possibly lazy) Logger suitable for system classes. 422 * Whether the returned logger is lazy or not depend on the result 423 * returned by {@link BootstrapLogger#useLazyLoggers()}. 424 * 425 * @param name the logger name 426 * @param caller the class on behalf of which the logger is created. 427 * @return a (possibly lazy) Logger instance. 428 */ 429 public static final Logger getLazyLogger(String name, Class<?> caller) { 430 431 // BootstrapLogger has the logic to determine whether a LazyLogger 432 // should be used. Usually, it is worth it only if: 433 // - the VM is not yet booted 434 // - or, the backend is JUL and there is no configuration 435 // - or, the backend is a custom backend, as we don't know what 436 // that is going to load... 437 // So if for instance the VM is booted and we use JUL with a custom 438 // configuration, we're not going to delay the creation of loggers... 439 final boolean useLazyLogger = BootstrapLogger.useLazyLoggers(); 440 if (useLazyLogger) { 441 return new JdkLazyLogger(name, caller); 442 } else { 443 // Directly invoke the LoggerFinder. 444 return getLoggerFromFinder(name, caller); 445 } 446 } 447 448 } | 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 package jdk.internal.logger; 27 28 import java.security.AccessController; 29 import java.security.PrivilegedAction; 30 import java.util.function.BiFunction; 31 import java.lang.System.LoggerFinder; 32 import java.lang.System.Logger; 33 import java.lang.ref.WeakReference; 34 import java.lang.reflect.Module; 35 import java.util.Objects; 36 import jdk.internal.misc.VM; 37 import sun.util.logging.PlatformLogger; 38 39 /** 40 * This class is a factory for Lazy Loggers; only system loggers can be 41 * Lazy Loggers. 42 */ 43 public final class LazyLoggers { 44 45 static final RuntimePermission LOGGERFINDER_PERMISSION = 46 new RuntimePermission("loggerFinder"); 47 48 private LazyLoggers() { 49 throw new InternalError(); 50 } 51 52 /** 53 * This class is used to hold the factories that a Lazy Logger will use 54 * to create (or map) its wrapped logger. 55 * @param <L> {@link Logger} or a subclass of {@link Logger}. 56 */ 57 private static final class LazyLoggerFactories<L extends Logger> { 58 59 /** 60 * A factory method to create an SPI logger. 61 * Usually, this will be something like LazyLoggers::getSystemLogger. 62 */ 63 final BiFunction<String, Module, L> loggerSupplier; 64 65 66 public LazyLoggerFactories(BiFunction<String, Module, L> loggerSupplier) { 67 this(Objects.requireNonNull(loggerSupplier), 68 (Void)null); 69 } 70 71 private LazyLoggerFactories(BiFunction<String, Module, L> loggerSupplier, 72 Void unused) { 73 this.loggerSupplier = loggerSupplier; 74 } 75 76 } 77 78 static interface LoggerAccessor { 79 /** 80 * The logger name. 81 * @return The name of the logger that is / will be lazily created. 82 */ 83 public String getLoggerName(); 84 85 /** 86 * Returns the wrapped logger object. 87 * @return the wrapped logger object. 88 */ 89 public Logger wrapped(); 90 91 /** 92 * A PlatformLogger.Bridge view of the wrapped logger object. 93 * @return A PlatformLogger.Bridge view of the wrapped logger object. 94 */ 95 public PlatformLogger.Bridge platform(); 96 } 97 98 /** 99 * The LazyLoggerAccessor class holds all the logic that delays the creation 100 * of the SPI logger until such a time that the VM is booted and the logger 101 * is actually used for logging. 102 * 103 * This class uses the services of the BootstrapLogger class to instantiate 104 * temporary loggers if appropriate. 105 */ 106 static final class LazyLoggerAccessor implements LoggerAccessor { 107 108 // The factories that will be used to create the logger lazyly 109 final LazyLoggerFactories<? extends Logger> factories; 110 111 // We need to pass the actual caller module when creating the logger. 112 private final WeakReference<Module> moduleRef; 113 114 // The name of the logger that will be created lazyly 115 final String name; 116 // The plain logger SPI object - null until it is accessed for the 117 // first time. 118 private volatile Logger w; 119 // A PlatformLogger.Bridge view of w. 120 private volatile PlatformLogger.Bridge p; 121 122 123 private LazyLoggerAccessor(String name, 124 LazyLoggerFactories<? extends Logger> factories, 125 Module module) { 126 this(Objects.requireNonNull(name), Objects.requireNonNull(factories), 127 Objects.requireNonNull(module), null); 128 } 129 130 private LazyLoggerAccessor(String name, 131 LazyLoggerFactories<? extends Logger> factories, 132 Module module, Void unused) { 133 this.name = name; 134 this.factories = factories; 135 this.moduleRef = new WeakReference<>(module); 136 } 137 138 /** 139 * The logger name. 140 * @return The name of the logger that is / will be lazily created. 141 */ 142 @Override 143 public String getLoggerName() { 144 return name; 145 } 146 147 // must be called in synchronized block 148 // set wrapped logger if not set 149 private void setWrappedIfNotSet(Logger wrapped) { 150 if (w == null) { 151 w = wrapped; 152 } 153 } 154 155 /** 254 if (this.w == bootstrap) { 255 this.w = null; this.p = null; 256 } 257 } 258 return this.wrapped(); 259 } 260 261 PlatformLogger.Bridge getConcretePlatformLogger(BootstrapLogger bootstrap) { 262 assert VM.isBooted(); 263 synchronized(this) { 264 // another thread may have already invoked flush() 265 if (this.w == bootstrap) { 266 this.w = null; this.p = null; 267 } 268 } 269 return this.platform(); 270 } 271 272 // Creates the wrapped logger by invoking the SPI. 273 Logger createLogger() { 274 final Module module = moduleRef.get(); 275 if (module == null) { 276 throw new IllegalStateException("The module for which this logger" 277 + " was created has been garbage collected"); 278 } 279 return this.factories.loggerSupplier.apply(name, module); 280 } 281 282 /** 283 * Creates a new lazy logger accessor for the named logger. The given 284 * factories will be use when it becomes necessary to actually create 285 * the logger. 286 * @param <T> An interface that extends {@link Logger}. 287 * @param name The logger name. 288 * @param factories The factories that should be used to create the 289 * wrapped logger. 290 * @return A new LazyLoggerAccessor. 291 */ 292 public static LazyLoggerAccessor makeAccessor(String name, 293 LazyLoggerFactories<? extends Logger> factories, Module module) { 294 return new LazyLoggerAccessor(name, factories, module); 295 } 296 297 } 298 299 /** 300 * An implementation of {@link Logger} that redirects all calls to a wrapped 301 * instance of {@code Logger}. 302 */ 303 private static class LazyLoggerWrapper 304 extends AbstractLoggerWrapper<Logger> { 305 306 final LoggerAccessor loggerAccessor; 307 308 public LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier) { 309 this(Objects.requireNonNull(loggerSinkSupplier), (Void)null); 310 } 311 312 private LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier, 313 Void unused) { 314 this.loggerAccessor = loggerSinkSupplier; 330 private static volatile LoggerFinder provider; 331 private static LoggerFinder accessLoggerFinder() { 332 LoggerFinder prov = provider; 333 if (prov == null) { 334 // no need to lock: it doesn't matter if we call 335 // getLoggerFinder() twice - since LoggerFinder already caches 336 // the result. 337 // This is just an optimization to avoid the cost of calling 338 // doPrivileged every time. 339 final SecurityManager sm = System.getSecurityManager(); 340 prov = sm == null ? LoggerFinder.getLoggerFinder() : 341 AccessController.doPrivileged( 342 (PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder); 343 provider = prov; 344 } 345 return prov; 346 } 347 348 // Avoid using lambda here as lazy loggers could be created early 349 // in the bootstrap sequence... 350 private static final BiFunction<String, Module, Logger> loggerSupplier = 351 new BiFunction<>() { 352 @Override 353 public Logger apply(String name, Module module) { 354 return LazyLoggers.getLoggerFromFinder(name, module); 355 } 356 }; 357 358 private static final LazyLoggerFactories<Logger> factories = 359 new LazyLoggerFactories<>(loggerSupplier); 360 361 362 363 // A concrete implementation of Logger that delegates to a System.Logger, 364 // but only creates the System.Logger instance lazily when it's used for 365 // the first time. 366 // The JdkLazyLogger uses a LazyLoggerAccessor objects, which relies 367 // on the logic embedded in BootstrapLogger to avoid loading the concrete 368 // logger provider until the VM has finished booting. 369 // 370 private static final class JdkLazyLogger extends LazyLoggerWrapper { 371 JdkLazyLogger(String name, Module module) { 372 this(LazyLoggerAccessor.makeAccessor(name, factories, module), 373 (Void)null); 374 } 375 private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { 376 super(holder); 377 } 378 } 379 380 /** 381 * Gets a logger from the LoggerFinder. Creates the actual concrete 382 * logger. 383 * @param name name of the logger 384 * @param module module on behalf of which the logger is created 385 * @return The logger returned by the LoggerFinder. 386 */ 387 static Logger getLoggerFromFinder(String name, Module module) { 388 final SecurityManager sm = System.getSecurityManager(); 389 if (sm == null) { 390 return accessLoggerFinder().getLogger(name, module); 391 } else { 392 return AccessController.doPrivileged((PrivilegedAction<Logger>) 393 () -> {return accessLoggerFinder().getLogger(name, module);}, 394 null, LOGGERFINDER_PERMISSION); 395 } 396 } 397 398 /** 399 * Returns a (possibly lazy) Logger for the caller. 400 * 401 * @param name the logger name 402 * @param module The module on behalf of which the logger is created. 403 * If the module is not loaded from the Boot ClassLoader, 404 * the LoggerFinder is accessed and the logger returned 405 * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.reflect.Module)} 406 * is returned to the caller directly. 407 * Otherwise, the logger returned by 408 * {@link #getLazyLogger(java.lang.String, java.lang.reflect.Module)} 409 * is returned to the caller. 410 * 411 * @return a (possibly lazy) Logger instance. 412 */ 413 public static final Logger getLogger(String name, Module module) { 414 if (DefaultLoggerFinder.isSystem(module)) { 415 return getLazyLogger(name, module); 416 } else { 417 return getLoggerFromFinder(name, module); 418 } 419 } 420 421 /** 422 * Returns a (possibly lazy) Logger suitable for system classes. 423 * Whether the returned logger is lazy or not depend on the result 424 * returned by {@link BootstrapLogger#useLazyLoggers()}. 425 * 426 * @param name the logger name 427 * @param module the module on behalf of which the logger is created. 428 * @return a (possibly lazy) Logger instance. 429 */ 430 public static final Logger getLazyLogger(String name, Module module) { 431 432 // BootstrapLogger has the logic to determine whether a LazyLogger 433 // should be used. Usually, it is worth it only if: 434 // - the VM is not yet booted 435 // - or, the backend is JUL and there is no configuration 436 // - or, the backend is a custom backend, as we don't know what 437 // that is going to load... 438 // So if for instance the VM is booted and we use JUL with a custom 439 // configuration, we're not going to delay the creation of loggers... 440 final boolean useLazyLogger = BootstrapLogger.useLazyLoggers(); 441 if (useLazyLogger) { 442 return new JdkLazyLogger(name, module); 443 } else { 444 // Directly invoke the LoggerFinder. 445 return getLoggerFromFinder(name, module); 446 } 447 } 448 449 } |