Home | History | Annotate | Download | only in impl
      1 /**
      2  * Copyright (c) 2004-2011 QOS.ch
      3  * All rights reserved.
      4  *
      5  * Permission is hereby granted, free  of charge, to any person obtaining
      6  * a  copy  of this  software  and  associated  documentation files  (the
      7  * "Software"), to  deal in  the Software without  restriction, including
      8  * without limitation  the rights to  use, copy, modify,  merge, publish,
      9  * distribute,  sublicense, and/or sell  copies of  the Software,  and to
     10  * permit persons to whom the Software  is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The  above  copyright  notice  and  this permission  notice  shall  be
     14  * included in all copies or substantial portions of the Software.
     15  *
     16  * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
     17  * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
     18  * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
     19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     21  * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
     22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  */
     25 package org.slf4j.impl;
     26 
     27 import java.util.logging.Level;
     28 import java.util.logging.LogRecord;
     29 
     30 import org.slf4j.Logger;
     31 import org.slf4j.Marker;
     32 import org.slf4j.helpers.FormattingTuple;
     33 import org.slf4j.helpers.MarkerIgnoringBase;
     34 import org.slf4j.helpers.MessageFormatter;
     35 import org.slf4j.spi.LocationAwareLogger;
     36 
     37 /**
     38  * A wrapper over {@link java.util.logging.Logger java.util.logging.Logger} in
     39  * conformity with the {@link Logger} interface. Note that the logging levels
     40  * mentioned in this class refer to those defined in the java.util.logging
     41  * package.
     42  *
     43  * @author Ceki Gülcü
     44  * @author Peter Royal
     45  */
     46 public final class JDK14LoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger {
     47 
     48     private static final long serialVersionUID = -8053026990503422791L;
     49 
     50     transient final java.util.logging.Logger logger;
     51 
     52     // WARN: JDK14LoggerAdapter constructor should have only package access so
     53     // that only JDK14LoggerFactory be able to create one.
     54     JDK14LoggerAdapter(java.util.logging.Logger logger) {
     55         this.logger = logger;
     56         this.name = logger.getName();
     57     }
     58 
     59     /**
     60      * Is this logger instance enabled for the FINEST level?
     61      *
     62      * @return True if this Logger is enabled for level FINEST, false otherwise.
     63      */
     64     public boolean isTraceEnabled() {
     65         return logger.isLoggable(Level.FINEST);
     66     }
     67 
     68     /**
     69      * Log a message object at level FINEST.
     70      *
     71      * @param msg
     72      *          - the message object to be logged
     73      */
     74     public void trace(String msg) {
     75         if (logger.isLoggable(Level.FINEST)) {
     76             log(SELF, Level.FINEST, msg, null);
     77         }
     78     }
     79 
     80     /**
     81      * Log a message at level FINEST according to the specified format and
     82      * argument.
     83      *
     84      * <p>
     85      * This form avoids superfluous object creation when the logger is disabled
     86      * for level FINEST.
     87      * </p>
     88      *
     89      * @param format
     90      *          the format string
     91      * @param arg
     92      *          the argument
     93      */
     94     public void trace(String format, Object arg) {
     95         if (logger.isLoggable(Level.FINEST)) {
     96             FormattingTuple ft = MessageFormatter.format(format, arg);
     97             log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
     98         }
     99     }
    100 
    101     /**
    102      * Log a message at level FINEST according to the specified format and
    103      * arguments.
    104      *
    105      * <p>
    106      * This form avoids superfluous object creation when the logger is disabled
    107      * for the FINEST level.
    108      * </p>
    109      *
    110      * @param format
    111      *          the format string
    112      * @param arg1
    113      *          the first argument
    114      * @param arg2
    115      *          the second argument
    116      */
    117     public void trace(String format, Object arg1, Object arg2) {
    118         if (logger.isLoggable(Level.FINEST)) {
    119             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    120             log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
    121         }
    122     }
    123 
    124     /**
    125      * Log a message at level FINEST according to the specified format and
    126      * arguments.
    127      *
    128      * <p>
    129      * This form avoids superfluous object creation when the logger is disabled
    130      * for the FINEST level.
    131      * </p>
    132      *
    133      * @param format
    134      *          the format string
    135      * @param argArray
    136      *          an array of arguments
    137      */
    138     public void trace(String format, Object... argArray) {
    139         if (logger.isLoggable(Level.FINEST)) {
    140             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    141             log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
    142         }
    143     }
    144 
    145     /**
    146      * Log an exception (throwable) at level FINEST with an accompanying message.
    147      *
    148      * @param msg
    149      *          the message accompanying the exception
    150      * @param t
    151      *          the exception (throwable) to log
    152      */
    153     public void trace(String msg, Throwable t) {
    154         if (logger.isLoggable(Level.FINEST)) {
    155             log(SELF, Level.FINEST, msg, t);
    156         }
    157     }
    158 
    159     /**
    160      * Is this logger instance enabled for the FINE level?
    161      *
    162      * @return True if this Logger is enabled for level FINE, false otherwise.
    163      */
    164     public boolean isDebugEnabled() {
    165         return logger.isLoggable(Level.FINE);
    166     }
    167 
    168     /**
    169      * Log a message object at level FINE.
    170      *
    171      * @param msg
    172      *          - the message object to be logged
    173      */
    174     public void debug(String msg) {
    175         if (logger.isLoggable(Level.FINE)) {
    176             log(SELF, Level.FINE, msg, null);
    177         }
    178     }
    179 
    180     /**
    181      * Log a message at level FINE according to the specified format and argument.
    182      *
    183      * <p>
    184      * This form avoids superfluous object creation when the logger is disabled
    185      * for level FINE.
    186      * </p>
    187      *
    188      * @param format
    189      *          the format string
    190      * @param arg
    191      *          the argument
    192      */
    193     public void debug(String format, Object arg) {
    194         if (logger.isLoggable(Level.FINE)) {
    195             FormattingTuple ft = MessageFormatter.format(format, arg);
    196             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    197         }
    198     }
    199 
    200     /**
    201      * Log a message at level FINE according to the specified format and
    202      * arguments.
    203      *
    204      * <p>
    205      * This form avoids superfluous object creation when the logger is disabled
    206      * for the FINE level.
    207      * </p>
    208      *
    209      * @param format
    210      *          the format string
    211      * @param arg1
    212      *          the first argument
    213      * @param arg2
    214      *          the second argument
    215      */
    216     public void debug(String format, Object arg1, Object arg2) {
    217         if (logger.isLoggable(Level.FINE)) {
    218             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    219             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    220         }
    221     }
    222 
    223     /**
    224      * Log a message at level FINE according to the specified format and
    225      * arguments.
    226      *
    227      * <p>
    228      * This form avoids superfluous object creation when the logger is disabled
    229      * for the FINE level.
    230      * </p>
    231      *
    232      * @param format
    233      *          the format string
    234      * @param argArray
    235      *          an array of arguments
    236      */
    237     public void debug(String format, Object... argArray) {
    238         if (logger.isLoggable(Level.FINE)) {
    239             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    240             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    241         }
    242     }
    243 
    244     /**
    245      * Log an exception (throwable) at level FINE with an accompanying message.
    246      *
    247      * @param msg
    248      *          the message accompanying the exception
    249      * @param t
    250      *          the exception (throwable) to log
    251      */
    252     public void debug(String msg, Throwable t) {
    253         if (logger.isLoggable(Level.FINE)) {
    254             log(SELF, Level.FINE, msg, t);
    255         }
    256     }
    257 
    258     /**
    259      * Is this logger instance enabled for the INFO level?
    260      *
    261      * @return True if this Logger is enabled for the INFO level, false otherwise.
    262      */
    263     public boolean isInfoEnabled() {
    264         return logger.isLoggable(Level.INFO);
    265     }
    266 
    267     /**
    268      * Log a message object at the INFO level.
    269      *
    270      * @param msg
    271      *          - the message object to be logged
    272      */
    273     public void info(String msg) {
    274         if (logger.isLoggable(Level.INFO)) {
    275             log(SELF, Level.INFO, msg, null);
    276         }
    277     }
    278 
    279     /**
    280      * Log a message at level INFO according to the specified format and argument.
    281      *
    282      * <p>
    283      * This form avoids superfluous object creation when the logger is disabled
    284      * for the INFO level.
    285      * </p>
    286      *
    287      * @param format
    288      *          the format string
    289      * @param arg
    290      *          the argument
    291      */
    292     public void info(String format, Object arg) {
    293         if (logger.isLoggable(Level.INFO)) {
    294             FormattingTuple ft = MessageFormatter.format(format, arg);
    295             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    296         }
    297     }
    298 
    299     /**
    300      * Log a message at the INFO level according to the specified format and
    301      * arguments.
    302      *
    303      * <p>
    304      * This form avoids superfluous object creation when the logger is disabled
    305      * for the INFO level.
    306      * </p>
    307      *
    308      * @param format
    309      *          the format string
    310      * @param arg1
    311      *          the first argument
    312      * @param arg2
    313      *          the second argument
    314      */
    315     public void info(String format, Object arg1, Object arg2) {
    316         if (logger.isLoggable(Level.INFO)) {
    317             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    318             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    319         }
    320     }
    321 
    322     /**
    323      * Log a message at level INFO according to the specified format and
    324      * arguments.
    325      *
    326      * <p>
    327      * This form avoids superfluous object creation when the logger is disabled
    328      * for the INFO level.
    329      * </p>
    330      *
    331      * @param format
    332      *          the format string
    333      * @param argArray
    334      *          an array of arguments
    335      */
    336     public void info(String format, Object... argArray) {
    337         if (logger.isLoggable(Level.INFO)) {
    338             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    339             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    340         }
    341     }
    342 
    343     /**
    344      * Log an exception (throwable) at the INFO level with an accompanying
    345      * message.
    346      *
    347      * @param msg
    348      *          the message accompanying the exception
    349      * @param t
    350      *          the exception (throwable) to log
    351      */
    352     public void info(String msg, Throwable t) {
    353         if (logger.isLoggable(Level.INFO)) {
    354             log(SELF, Level.INFO, msg, t);
    355         }
    356     }
    357 
    358     /**
    359      * Is this logger instance enabled for the WARNING level?
    360      *
    361      * @return True if this Logger is enabled for the WARNING level, false
    362      *         otherwise.
    363      */
    364     public boolean isWarnEnabled() {
    365         return logger.isLoggable(Level.WARNING);
    366     }
    367 
    368     /**
    369      * Log a message object at the WARNING level.
    370      *
    371      * @param msg
    372      *          - the message object to be logged
    373      */
    374     public void warn(String msg) {
    375         if (logger.isLoggable(Level.WARNING)) {
    376             log(SELF, Level.WARNING, msg, null);
    377         }
    378     }
    379 
    380     /**
    381      * Log a message at the WARNING level according to the specified format and
    382      * argument.
    383      *
    384      * <p>
    385      * This form avoids superfluous object creation when the logger is disabled
    386      * for the WARNING level.
    387      * </p>
    388      *
    389      * @param format
    390      *          the format string
    391      * @param arg
    392      *          the argument
    393      */
    394     public void warn(String format, Object arg) {
    395         if (logger.isLoggable(Level.WARNING)) {
    396             FormattingTuple ft = MessageFormatter.format(format, arg);
    397             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    398         }
    399     }
    400 
    401     /**
    402      * Log a message at the WARNING level according to the specified format and
    403      * arguments.
    404      *
    405      * <p>
    406      * This form avoids superfluous object creation when the logger is disabled
    407      * for the WARNING level.
    408      * </p>
    409      *
    410      * @param format
    411      *          the format string
    412      * @param arg1
    413      *          the first argument
    414      * @param arg2
    415      *          the second argument
    416      */
    417     public void warn(String format, Object arg1, Object arg2) {
    418         if (logger.isLoggable(Level.WARNING)) {
    419             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    420             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    421         }
    422     }
    423 
    424     /**
    425      * Log a message at level WARNING according to the specified format and
    426      * arguments.
    427      *
    428      * <p>
    429      * This form avoids superfluous object creation when the logger is disabled
    430      * for the WARNING level.
    431      * </p>
    432      *
    433      * @param format
    434      *          the format string
    435      * @param argArray
    436      *          an array of arguments
    437      */
    438     public void warn(String format, Object... argArray) {
    439         if (logger.isLoggable(Level.WARNING)) {
    440             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    441             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    442         }
    443     }
    444 
    445     /**
    446      * Log an exception (throwable) at the WARNING level with an accompanying
    447      * message.
    448      *
    449      * @param msg
    450      *          the message accompanying the exception
    451      * @param t
    452      *          the exception (throwable) to log
    453      */
    454     public void warn(String msg, Throwable t) {
    455         if (logger.isLoggable(Level.WARNING)) {
    456             log(SELF, Level.WARNING, msg, t);
    457         }
    458     }
    459 
    460     /**
    461      * Is this logger instance enabled for level SEVERE?
    462      *
    463      * @return True if this Logger is enabled for level SEVERE, false otherwise.
    464      */
    465     public boolean isErrorEnabled() {
    466         return logger.isLoggable(Level.SEVERE);
    467     }
    468 
    469     /**
    470      * Log a message object at the SEVERE level.
    471      *
    472      * @param msg
    473      *          - the message object to be logged
    474      */
    475     public void error(String msg) {
    476         if (logger.isLoggable(Level.SEVERE)) {
    477             log(SELF, Level.SEVERE, msg, null);
    478         }
    479     }
    480 
    481     /**
    482      * Log a message at the SEVERE level according to the specified format and
    483      * argument.
    484      *
    485      * <p>
    486      * This form avoids superfluous object creation when the logger is disabled
    487      * for the SEVERE level.
    488      * </p>
    489      *
    490      * @param format
    491      *          the format string
    492      * @param arg
    493      *          the argument
    494      */
    495     public void error(String format, Object arg) {
    496         if (logger.isLoggable(Level.SEVERE)) {
    497             FormattingTuple ft = MessageFormatter.format(format, arg);
    498             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    499         }
    500     }
    501 
    502     /**
    503      * Log a message at the SEVERE level according to the specified format and
    504      * arguments.
    505      *
    506      * <p>
    507      * This form avoids superfluous object creation when the logger is disabled
    508      * for the SEVERE level.
    509      * </p>
    510      *
    511      * @param format
    512      *          the format string
    513      * @param arg1
    514      *          the first argument
    515      * @param arg2
    516      *          the second argument
    517      */
    518     public void error(String format, Object arg1, Object arg2) {
    519         if (logger.isLoggable(Level.SEVERE)) {
    520             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    521             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    522         }
    523     }
    524 
    525     /**
    526      * Log a message at level SEVERE according to the specified format and
    527      * arguments.
    528      *
    529      * <p>
    530      * This form avoids superfluous object creation when the logger is disabled
    531      * for the SEVERE level.
    532      * </p>
    533      *
    534      * @param format
    535      *          the format string
    536      * @param arguments
    537      *          an array of arguments
    538      */
    539     public void error(String format, Object... arguments) {
    540         if (logger.isLoggable(Level.SEVERE)) {
    541             FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
    542             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    543         }
    544     }
    545 
    546     /**
    547      * Log an exception (throwable) at the SEVERE level with an accompanying
    548      * message.
    549      *
    550      * @param msg
    551      *          the message accompanying the exception
    552      * @param t
    553      *          the exception (throwable) to log
    554      */
    555     public void error(String msg, Throwable t) {
    556         if (logger.isLoggable(Level.SEVERE)) {
    557             log(SELF, Level.SEVERE, msg, t);
    558         }
    559     }
    560 
    561     /**
    562      * Log the message at the specified level with the specified throwable if any.
    563      * This method creates a LogRecord and fills in caller date before calling
    564      * this instance's JDK14 logger.
    565      *
    566      * See bug report #13 for more details.
    567      *
    568      * @param level
    569      * @param msg
    570      * @param t
    571      */
    572     private void log(String callerFQCN, Level level, String msg, Throwable t) {
    573         // millis and thread are filled by the constructor
    574         LogRecord record = new LogRecord(level, msg);
    575         record.setLoggerName(getName());
    576         record.setThrown(t);
    577         fillCallerData(callerFQCN, record);
    578         logger.log(record);
    579 
    580     }
    581 
    582     static String SELF = JDK14LoggerAdapter.class.getName();
    583     static String SUPER = MarkerIgnoringBase.class.getName();
    584 
    585     /**
    586      * Fill in caller data if possible.
    587      *
    588      * @param record
    589      *          The record to update
    590      */
    591     final private void fillCallerData(String callerFQCN, LogRecord record) {
    592         StackTraceElement[] steArray = new Throwable().getStackTrace();
    593 
    594         int selfIndex = -1;
    595         for (int i = 0; i < steArray.length; i++) {
    596             final String className = steArray[i].getClassName();
    597             if (className.equals(callerFQCN) || className.equals(SUPER)) {
    598                 selfIndex = i;
    599                 break;
    600             }
    601         }
    602 
    603         int found = -1;
    604         for (int i = selfIndex + 1; i < steArray.length; i++) {
    605             final String className = steArray[i].getClassName();
    606             if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
    607                 found = i;
    608                 break;
    609             }
    610         }
    611 
    612         if (found != -1) {
    613             StackTraceElement ste = steArray[found];
    614             // setting the class name has the side effect of setting
    615             // the needToInferCaller variable to false.
    616             record.setSourceClassName(ste.getClassName());
    617             record.setSourceMethodName(ste.getMethodName());
    618         }
    619     }
    620 
    621     public void log(Marker marker, String callerFQCN, int level, String message, Object[] argArray, Throwable t) {
    622         Level julLevel;
    623         switch (level) {
    624         case LocationAwareLogger.TRACE_INT:
    625             julLevel = Level.FINEST;
    626             break;
    627         case LocationAwareLogger.DEBUG_INT:
    628             julLevel = Level.FINE;
    629             break;
    630         case LocationAwareLogger.INFO_INT:
    631             julLevel = Level.INFO;
    632             break;
    633         case LocationAwareLogger.WARN_INT:
    634             julLevel = Level.WARNING;
    635             break;
    636         case LocationAwareLogger.ERROR_INT:
    637             julLevel = Level.SEVERE;
    638             break;
    639         default:
    640             throw new IllegalStateException("Level number " + level + " is not recognized.");
    641         }
    642         // the logger.isLoggable check avoids the unconditional
    643         // construction of location data for disabled log
    644         // statements. As of 2008-07-31, callers of this method
    645         // do not perform this check. See also
    646         // http://bugzilla.slf4j.org/show_bug.cgi?id=90
    647         if (logger.isLoggable(julLevel)) {
    648             log(callerFQCN, julLevel, message, t);
    649         }
    650     }
    651 }
    652