< prev index next >

src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java

Print this page




  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 }
< prev index next >