Home | History | Annotate | Download | only in logging
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 
     28 package sun.util.logging;
     29 
     30 import java.lang.ref.WeakReference;
     31 import java.io.PrintStream;
     32 import java.io.PrintWriter;
     33 import java.io.StringWriter;
     34 import java.security.AccessController;
     35 import java.security.PrivilegedAction;
     36 import java.util.Arrays;
     37 import java.util.Date;
     38 import java.util.HashMap;
     39 import java.util.Map;
     40 
     41 /**
     42  * Platform logger provides an API for the JRE components to log
     43  * messages.  This enables the runtime components to eliminate the
     44  * static dependency of the logging facility and also defers the
     45  * java.util.logging initialization until it is enabled.
     46  * In addition, the PlatformLogger API can be used if the logging
     47  * module does not exist.
     48  *
     49  * If the logging facility is not enabled, the platform loggers
     50  * will output log messages per the default logging configuration
     51  * (see below). In this implementation, it does not log the
     52  * 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 platform
     56  * logger and all log messages will be forwarded to the Logger
     57  * to handle.
     58  *
     59  * Logging facility is "enabled" when one of the following
     60  * conditions is met:
     61  * 1) a system property "java.util.logging.config.class" or
     62  *    "java.util.logging.config.file" is set
     63  * 2) java.util.logging.LogManager or java.util.logging.Logger
     64  *    is referenced that will trigger the logging initialization.
     65  *
     66  * Default logging configuration:
     67  *   global logging level = INFO
     68  *   handlers = java.util.logging.ConsoleHandler
     69  *   java.util.logging.ConsoleHandler.level = INFO
     70  *   java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
     71  *
     72  * Limitation:
     73  * <JAVA_HOME>/lib/logging.properties is the system-wide logging
     74  * configuration defined in the specification and read in the
     75  * default case to configure any java.util.logging.Logger instances.
     76  * Platform loggers will not detect if <JAVA_HOME>/lib/logging.properties
     77  * is modified. In other words, unless the java.util.logging API
     78  * 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 and
     81  * this limitation can be workaround with setting
     82  * -Djava.util.logging.config.file system property.
     83  *
     84  * @since 1.7
     85  */
     86 public class PlatformLogger {
     87     /*
     88      * These constants should be shortcuts to Level enum constants that
     89      * the clients of sun.util.logging.PlatformLogger require no source
     90      * modification and avoid the conversion from int to Level enum.
     91      *
     92      * This can be done when JavaFX is converted to use the new PlatformLogger.Level API.
     93      */
     94     public static final int OFF     = Integer.MAX_VALUE;
     95     public static final int SEVERE  = 1000;
     96     public static final int WARNING = 900;
     97     public static final int INFO    = 800;
     98     public static final int CONFIG  = 700;
     99     public static final int FINE    = 500;
    100     public static final int FINER   = 400;
    101     public static final int FINEST  = 300;
    102     public static final int ALL     = Integer.MIN_VALUE;
    103 
    104     /**
    105      * PlatformLogger logging levels.
    106      */
    107     public static enum Level {
    108         // The name and value must match that of {@code java.util.logging.Level}s.
    109         // Declare in ascending order of the given value for binary search.
    110         ALL,
    111         FINEST,
    112         FINER,
    113         FINE,
    114         CONFIG,
    115         INFO,
    116         WARNING,
    117         SEVERE,
    118         OFF;
    119 
    120         /**
    121          * Associated java.util.logging.Level lazily initialized in
    122          * JavaLoggerProxy's static initializer only once
    123          * when java.util.logging is available and enabled.
    124          * Only accessed by JavaLoggerProxy.
    125          */
    126         /* java.util.logging.Level */ Object javaLevel;
    127 
    128         // ascending order for binary search matching the list of enum constants
    129         private static final int[] levelValues = new int[] {
    130             PlatformLogger.ALL, PlatformLogger.FINEST, PlatformLogger.FINER,
    131             PlatformLogger.FINE, PlatformLogger.CONFIG, PlatformLogger.INFO,
    132             PlatformLogger.WARNING, PlatformLogger.SEVERE, PlatformLogger.OFF
    133         };
    134 
    135         public int intValue() {
    136             return levelValues[this.ordinal()];
    137         }
    138 
    139         static Level valueOf(int level) {
    140             switch (level) {
    141                 // ordering per the highest occurences in the jdk source
    142                 // finest, fine, finer, info first
    143                 case PlatformLogger.FINEST  : return Level.FINEST;
    144                 case PlatformLogger.FINE    : return Level.FINE;
    145                 case PlatformLogger.FINER   : return Level.FINER;
    146                 case PlatformLogger.INFO    : return Level.INFO;
    147                 case PlatformLogger.WARNING : return Level.WARNING;
    148                 case PlatformLogger.CONFIG  : return Level.CONFIG;
    149                 case PlatformLogger.SEVERE  : return Level.SEVERE;
    150                 case PlatformLogger.OFF     : return Level.OFF;
    151                 case PlatformLogger.ALL     : return Level.ALL;
    152             }
    153             // return the nearest Level value >= the given level,
    154             // for level > SEVERE, return SEVERE and exclude OFF
    155             int i = Arrays.binarySearch(levelValues, 0, levelValues.length-2, level);
    156             return values()[i >= 0 ? i : (-i-1)];
    157         }
    158     }
    159 
    160     private static final Level DEFAULT_LEVEL = Level.INFO;
    161     private static boolean loggingEnabled;
    162     static {
    163         loggingEnabled = AccessController.doPrivileged(
    164             new PrivilegedAction<Boolean>() {
    165                 public Boolean run() {
    166                     String cname = System.getProperty("java.util.logging.config.class");
    167                     String fname = System.getProperty("java.util.logging.config.file");
    168                     return (cname != null || fname != null);
    169                 }
    170             });
    171 
    172         // Android-removed: Unnecessary on android, and gets in the way of obfuscated
    173         // releases.
    174         //
    175         // force loading of all JavaLoggerProxy (sub)classes to make JIT de-optimizations
    176         // less probable.  Don't initialize JavaLoggerProxy class since
    177         // java.util.logging may not be enabled.
    178         //
    179         // try {
    180         //     Class.forName("sun.util.logging.PlatformLogger$DefaultLoggerProxy",
    181         //                   false,
    182         //                   PlatformLogger.class.getClassLoader());
    183         //     Class.forName("sun.util.logging.PlatformLogger$JavaLoggerProxy",
    184         //                   false,   // do not invoke class initializer
    185         //                   PlatformLogger.class.getClassLoader());
    186         // } catch (ClassNotFoundException ex) {
    187         //     throw new InternalError(ex.getMessage());
    188         // }
    189     }
    190 
    191     // Table of known loggers.  Maps names to PlatformLoggers.
    192     private static Map<String,WeakReference<PlatformLogger>> loggers =
    193         new HashMap<>();
    194 
    195     /**
    196      * Returns a PlatformLogger of a given name.
    197      */
    198     public static synchronized PlatformLogger getLogger(String name) {
    199         PlatformLogger log = null;
    200         WeakReference<PlatformLogger> ref = loggers.get(name);
    201         if (ref != null) {
    202             log = ref.get();
    203         }
    204         if (log == null) {
    205             log = new PlatformLogger(name);
    206             loggers.put(name, new WeakReference<>(log));
    207         }
    208         return log;
    209     }
    210 
    211     /**
    212      * Initialize java.util.logging.Logger objects for all platform loggers.
    213      * This method is called from LogManager.readPrimordialConfiguration().
    214      */
    215     public static synchronized void redirectPlatformLoggers() {
    216         if (loggingEnabled || !LoggingSupport.isAvailable()) return;
    217 
    218         loggingEnabled = true;
    219         for (Map.Entry<String, WeakReference<PlatformLogger>> entry : loggers.entrySet()) {
    220             WeakReference<PlatformLogger> ref = entry.getValue();
    221             PlatformLogger plog = ref.get();
    222             if (plog != null) {
    223                 plog.redirectToJavaLoggerProxy();
    224             }
    225         }
    226     }
    227 
    228     /**
    229      * Creates a new JavaLoggerProxy and redirects the platform logger to it
    230      */
    231     private void redirectToJavaLoggerProxy() {
    232         DefaultLoggerProxy lp = DefaultLoggerProxy.class.cast(this.loggerProxy);
    233         JavaLoggerProxy jlp = new JavaLoggerProxy(lp.name, lp.level);
    234         // the order of assignments is important
    235         this.javaLoggerProxy = jlp;   // isLoggable checks javaLoggerProxy if set
    236         this.loggerProxy = jlp;
    237     }
    238 
    239     // DefaultLoggerProxy may be replaced with a JavaLoggerProxy object
    240     // when the java.util.logging facility is enabled
    241     private volatile LoggerProxy loggerProxy;
    242     // javaLoggerProxy is only set when the java.util.logging facility is enabled
    243     private volatile JavaLoggerProxy javaLoggerProxy;
    244     private PlatformLogger(String name) {
    245         if (loggingEnabled) {
    246             this.loggerProxy = this.javaLoggerProxy = new JavaLoggerProxy(name);
    247         } else {
    248             this.loggerProxy = new DefaultLoggerProxy(name);
    249         }
    250     }
    251 
    252     /**
    253      * A convenience method to test if the logger is turned off.
    254      * (i.e. its level is OFF).
    255      */
    256     public boolean isEnabled() {
    257         return loggerProxy.isEnabled();
    258     }
    259 
    260     /**
    261      * Gets the name for this platform logger.
    262      */
    263     public String getName() {
    264         return loggerProxy.name;
    265     }
    266 
    267     /**
    268      * Returns true if a message of the given level would actually
    269      * be logged by this logger.
    270      *
    271      * @deprecated Use isLoggable(Level) instead.
    272      */
    273     @Deprecated
    274     public boolean isLoggable(int levelValue) {
    275         return isLoggable(Level.valueOf(levelValue));
    276     }
    277 
    278     /**
    279      * Gets the current log level. Returns 0 if the current effective level is
    280      * not set (equivalent to Logger.getLevel() returns null).
    281      *
    282      * @deprecated Use level() instead
    283      */
    284     @Deprecated
    285     public int getLevel() {
    286         Level level = loggerProxy.getLevel();
    287         return level != null ? level.intValue() : 0;
    288     }
    289 
    290     /**
    291      * Sets the log level.
    292      *
    293      * @deprecated Use setLevel(Level) instead
    294      */
    295     @Deprecated
    296     public void setLevel(int newLevel) {
    297         loggerProxy.setLevel(newLevel == 0 ? null : Level.valueOf(newLevel));
    298     }
    299 
    300     /**
    301      * Returns true if a message of the given level would actually
    302      * be logged by this logger.
    303      */
    304     public boolean isLoggable(Level level) {
    305         if (level == null) {
    306             throw new NullPointerException();
    307         }
    308         // performance-sensitive method: use two monomorphic call-sites
    309         JavaLoggerProxy jlp = javaLoggerProxy;
    310         return jlp != null ? jlp.isLoggable(level) : loggerProxy.isLoggable(level);
    311     }
    312 
    313     /**
    314      * Get the log level that has been specified for this PlatformLogger.
    315      * The result may be null, which means that this logger's
    316      * effective level will be inherited from its parent.
    317      *
    318      * @return  this PlatformLogger's level
    319      */
    320     public Level level() {
    321         return loggerProxy.getLevel();
    322     }
    323 
    324     /**
    325      * Set the log level specifying which message levels will be
    326      * logged by this logger.  Message levels lower than this
    327      * value will be discarded.  The level value {@link #OFF}
    328      * can be used to turn off logging.
    329      * <p>
    330      * If the new level is null, it means that this node should
    331      * inherit its level from its nearest ancestor with a specific
    332      * (non-null) level value.
    333      *
    334      * @param newLevel the new value for the log level (may be null)
    335      */
    336     public void setLevel(Level newLevel) {
    337         loggerProxy.setLevel(newLevel);
    338     }
    339 
    340     /**
    341      * Logs a SEVERE message.
    342      */
    343     public void severe(String msg) {
    344         loggerProxy.doLog(Level.SEVERE, msg);
    345     }
    346 
    347     public void severe(String msg, Throwable t) {
    348         loggerProxy.doLog(Level.SEVERE, msg, t);
    349     }
    350 
    351     public void severe(String msg, Object... params) {
    352         loggerProxy.doLog(Level.SEVERE, msg, params);
    353     }
    354 
    355     /**
    356      * Logs a WARNING message.
    357      */
    358     public void warning(String msg) {
    359         loggerProxy.doLog(Level.WARNING, msg);
    360     }
    361 
    362     public void warning(String msg, Throwable t) {
    363         loggerProxy.doLog(Level.WARNING, msg, t);
    364     }
    365 
    366     public void warning(String msg, Object... params) {
    367         loggerProxy.doLog(Level.WARNING, msg, params);
    368     }
    369 
    370     /**
    371      * Logs an INFO message.
    372      */
    373     public void info(String msg) {
    374         loggerProxy.doLog(Level.INFO, msg);
    375     }
    376 
    377     public void info(String msg, Throwable t) {
    378         loggerProxy.doLog(Level.INFO, msg, t);
    379     }
    380 
    381     public void info(String msg, Object... params) {
    382         loggerProxy.doLog(Level.INFO, msg, params);
    383     }
    384 
    385     /**
    386      * Logs a CONFIG message.
    387      */
    388     public void config(String msg) {
    389         loggerProxy.doLog(Level.CONFIG, msg);
    390     }
    391 
    392     public void config(String msg, Throwable t) {
    393         loggerProxy.doLog(Level.CONFIG, msg, t);
    394     }
    395 
    396     public void config(String msg, Object... params) {
    397         loggerProxy.doLog(Level.CONFIG, msg, params);
    398     }
    399 
    400     /**
    401      * Logs a FINE message.
    402      */
    403     public void fine(String msg) {
    404         loggerProxy.doLog(Level.FINE, msg);
    405     }
    406 
    407     public void fine(String msg, Throwable t) {
    408         loggerProxy.doLog(Level.FINE, msg, t);
    409     }
    410 
    411     public void fine(String msg, Object... params) {
    412         loggerProxy.doLog(Level.FINE, msg, params);
    413     }
    414 
    415     /**
    416      * Logs a FINER message.
    417      */
    418     public void finer(String msg) {
    419         loggerProxy.doLog(Level.FINER, msg);
    420     }
    421 
    422     public void finer(String msg, Throwable t) {
    423         loggerProxy.doLog(Level.FINER, msg, t);
    424     }
    425 
    426     public void finer(String msg, Object... params) {
    427         loggerProxy.doLog(Level.FINER, msg, params);
    428     }
    429 
    430     /**
    431      * Logs a FINEST message.
    432      */
    433     public void finest(String msg) {
    434         loggerProxy.doLog(Level.FINEST, msg);
    435     }
    436 
    437     public void finest(String msg, Throwable t) {
    438         loggerProxy.doLog(Level.FINEST, msg, t);
    439     }
    440 
    441     public void finest(String msg, Object... params) {
    442         loggerProxy.doLog(Level.FINEST, msg, params);
    443     }
    444 
    445     /**
    446      * Abstract base class for logging support, defining the API and common field.
    447      */
    448     private static abstract class LoggerProxy {
    449         final String name;
    450 
    451         protected LoggerProxy(String name) {
    452             this.name = name;
    453         }
    454 
    455         abstract boolean isEnabled();
    456 
    457         abstract Level getLevel();
    458         abstract void setLevel(Level newLevel);
    459 
    460         abstract void doLog(Level level, String msg);
    461         abstract void doLog(Level level, String msg, Throwable thrown);
    462         abstract void doLog(Level level, String msg, Object... params);
    463 
    464         abstract boolean isLoggable(Level level);
    465     }
    466 
    467 
    468     private static final class DefaultLoggerProxy extends LoggerProxy {
    469         /**
    470          * Default platform logging support - output messages to System.err -
    471          * equivalent to ConsoleHandler with SimpleFormatter.
    472          */
    473         private static PrintStream outputStream() {
    474             return System.err;
    475         }
    476 
    477         volatile Level effectiveLevel; // effective level (never null)
    478         volatile Level level;          // current level set for this node (may be null)
    479 
    480         DefaultLoggerProxy(String name) {
    481             super(name);
    482             this.effectiveLevel = deriveEffectiveLevel(null);
    483             this.level = null;
    484         }
    485 
    486         boolean isEnabled() {
    487             return effectiveLevel != Level.OFF;
    488         }
    489 
    490         Level getLevel() {
    491             return level;
    492         }
    493 
    494         void setLevel(Level newLevel) {
    495             Level oldLevel = level;
    496             if (oldLevel != newLevel) {
    497                 level = newLevel;
    498                 effectiveLevel = deriveEffectiveLevel(newLevel);
    499             }
    500         }
    501 
    502         void doLog(Level level, String msg) {
    503             if (isLoggable(level)) {
    504                 outputStream().print(format(level, msg, null));
    505             }
    506         }
    507 
    508         void doLog(Level level, String msg, Throwable thrown) {
    509             if (isLoggable(level)) {
    510                 outputStream().print(format(level, msg, thrown));
    511             }
    512         }
    513 
    514         void doLog(Level level, String msg, Object... params) {
    515             if (isLoggable(level)) {
    516                 String newMsg = formatMessage(msg, params);
    517                 outputStream().print(format(level, newMsg, null));
    518             }
    519         }
    520 
    521         boolean isLoggable(Level level) {
    522             Level effectiveLevel = this.effectiveLevel;
    523             return level.intValue() >= effectiveLevel.intValue() && effectiveLevel != Level.OFF;
    524         }
    525 
    526         // derive effective level (could do inheritance search like j.u.l.Logger)
    527         private Level deriveEffectiveLevel(Level level) {
    528             return level == null ? DEFAULT_LEVEL : level;
    529         }
    530 
    531         // Copied from java.util.logging.Formatter.formatMessage
    532         private String formatMessage(String format, Object... parameters) {
    533             // Do the formatting.
    534             try {
    535                 if (parameters == null || parameters.length == 0) {
    536                     // No parameters.  Just return format string.
    537                     return format;
    538                 }
    539                 // Is it a java.text style format?
    540                 // Ideally we could match with
    541                 // Pattern.compile("\\{\\d").matcher(format).find())
    542                 // However the cost is 14% higher, so we cheaply check for
    543                 // 1 of the first 4 parameters
    544                 if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
    545                             format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
    546                     return java.text.MessageFormat.format(format, parameters);
    547                 }
    548                 return format;
    549             } catch (Exception ex) {
    550                 // Formatting failed: use format string.
    551                 return format;
    552             }
    553         }
    554 
    555         private static final String formatString =
    556             LoggingSupport.getSimpleFormat(false); // don't check logging.properties
    557 
    558         // minimize memory allocation
    559         private Date date = new Date();
    560         private synchronized String format(Level level, String msg, Throwable thrown) {
    561             date.setTime(System.currentTimeMillis());
    562             String throwable = "";
    563             if (thrown != null) {
    564                 StringWriter sw = new StringWriter();
    565                 PrintWriter pw = new PrintWriter(sw);
    566                 pw.println();
    567                 thrown.printStackTrace(pw);
    568                 pw.close();
    569                 throwable = sw.toString();
    570             }
    571 
    572             return String.format(formatString,
    573                                  date,
    574                                  getCallerInfo(),
    575                                  name,
    576                                  level.name(),
    577                                  msg,
    578                                  throwable);
    579         }
    580 
    581         // Returns the caller's class and method's name; best effort
    582         // if cannot infer, return the logger's name.
    583         private String getCallerInfo() {
    584             String sourceClassName = null;
    585             String sourceMethodName = null;
    586 
    587             Throwable throwable = new Throwable();
    588 
    589             String logClassName = "sun.util.logging.PlatformLogger";
    590             boolean lookingForLogger = true;
    591             for (StackTraceElement frame : throwable.getStackTrace()) {
    592                 String cname = frame.getClassName();
    593                 if (lookingForLogger) {
    594                     // Skip all frames until we have found the first logger frame.
    595                     if (cname.equals(logClassName)) {
    596                         lookingForLogger = false;
    597                     }
    598                 } else {
    599                     if (!cname.equals(logClassName)) {
    600                         // We've found the relevant frame.
    601                         sourceClassName = cname;
    602                         sourceMethodName = frame.getMethodName();
    603                         break;
    604                     }
    605                 }
    606             }
    607 
    608             if (sourceClassName != null) {
    609                 return sourceClassName + " " + sourceMethodName;
    610             } else {
    611                 return name;
    612             }
    613         }
    614     }
    615 
    616     /**
    617      * JavaLoggerProxy forwards all the calls to its corresponding
    618      * java.util.logging.Logger object.
    619      */
    620     private static final class JavaLoggerProxy extends LoggerProxy {
    621         // initialize javaLevel fields for mapping from Level enum -> j.u.l.Level object
    622         static {
    623             for (Level level : Level.values()) {
    624                 level.javaLevel = LoggingSupport.parseLevel(level.name());
    625             }
    626         }
    627 
    628         private final /* java.util.logging.Logger */ Object javaLogger;
    629 
    630         JavaLoggerProxy(String name) {
    631             this(name, null);
    632         }
    633 
    634         JavaLoggerProxy(String name, Level level) {
    635             super(name);
    636             this.javaLogger = LoggingSupport.getLogger(name);
    637             if (level != null) {
    638                 // level has been updated and so set the Logger's level
    639                 LoggingSupport.setLevel(javaLogger, level.javaLevel);
    640             }
    641         }
    642 
    643         void doLog(Level level, String msg) {
    644             LoggingSupport.log(javaLogger, level.javaLevel, msg);
    645         }
    646 
    647         void doLog(Level level, String msg, Throwable t) {
    648             LoggingSupport.log(javaLogger, level.javaLevel, msg, t);
    649         }
    650 
    651         void doLog(Level level, String msg, Object... params) {
    652             if (!isLoggable(level)) {
    653                 return;
    654             }
    655             // only pass String objects to the j.u.l.Logger which may
    656             // be created by untrusted code
    657             int len = (params != null) ? params.length : 0;
    658             Object[] sparams = new String[len];
    659             for (int i = 0; i < len; i++) {
    660                 sparams [i] = String.valueOf(params[i]);
    661             }
    662             LoggingSupport.log(javaLogger, level.javaLevel, msg, sparams);
    663         }
    664 
    665         boolean isEnabled() {
    666             return LoggingSupport.isLoggable(javaLogger, Level.OFF.javaLevel);
    667         }
    668 
    669         /**
    670          * Returns the PlatformLogger.Level mapped from j.u.l.Level
    671          * set in the logger.  If the j.u.l.Logger is set to a custom Level,
    672          * this method will return the nearest Level.
    673          */
    674         Level getLevel() {
    675             Object javaLevel = LoggingSupport.getLevel(javaLogger);
    676             if (javaLevel == null) return null;
    677 
    678             try {
    679                 return Level.valueOf(LoggingSupport.getLevelName(javaLevel));
    680             } catch (IllegalArgumentException e) {
    681                 return Level.valueOf(LoggingSupport.getLevelValue(javaLevel));
    682             }
    683         }
    684 
    685         void setLevel(Level level) {
    686             LoggingSupport.setLevel(javaLogger, level == null ? null : level.javaLevel);
    687         }
    688 
    689         boolean isLoggable(Level level) {
    690             return LoggingSupport.isLoggable(javaLogger, level.javaLevel);
    691         }
    692     }
    693 }
    694