View Javadoc

    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.event.EventConstants;
    33  import org.slf4j.event.LoggingEvent;
    34  import org.slf4j.helpers.FormattingTuple;
    35  import org.slf4j.helpers.MarkerIgnoringBase;
    36  import org.slf4j.helpers.MessageFormatter;
    37  import org.slf4j.spi.LocationAwareLogger;
    38
    39  /**
    40   * A wrapper over {@link java.util.logging.Logger java.util.logging.Logger} in
    41   * conformity with the {@link Logger} interface. Note that the logging levels
    42   * mentioned in this class refer to those defined in the java.util.logging
    43   * package.
    44   *
    45   * @author Ceki G&uuml;lc&uuml;
    46   * @author Peter Royal
    47   */
    48  public final class JDK14LoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger {
    49
    50      private static final long serialVersionUID = -8053026990503422791L;
    51
    52      transient final java.util.logging.Logger logger;
    53
    54      // WARN: JDK14LoggerAdapter constructor should have only package access so
    55      // that only JDK14LoggerFactory be able to create one.
    56      JDK14LoggerAdapter(java.util.logging.Logger logger) {
    57          this.logger = logger;
    58          this.name = logger.getName();
    59      }
    60
    61      /**
    62       * Is this logger instance enabled for the FINEST level?
    63       *
    64       * @return True if this Logger is enabled for level FINEST, false otherwise.
    65       */
    66      public boolean isTraceEnabled() {
    67          return logger.isLoggable(Level.FINEST);
    68      }
    69
    70      /**
    71       * Log a message object at level FINEST.
    72       *
    73       * @param msg
    74       *          - the message object to be logged
    75       */
    76      public void trace(String msg) {
    77          if (logger.isLoggable(Level.FINEST)) {
    78              log(SELF, Level.FINEST, msg, null);
    79          }
    80      }
    81
    82      /**
    83       * Log a message at level FINEST according to the specified format and
    84       * argument.
    85       *
    86       * <p>
    87       * This form avoids superfluous object creation when the logger is disabled
    88       * for level FINEST.
    89       * </p>
    90       *
    91       * @param format
    92       *          the format string
    93       * @param arg
    94       *          the argument
    95       */
    96      public void trace(String format, Object arg) {
    97          if (logger.isLoggable(Level.FINEST)) {
    98              FormattingTuple ft = MessageFormatter.format(format, arg);
    99              log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
    100         }
    101     }
    102
    103     /**
    104      * Log a message at level FINEST according to the specified format and
    105      * arguments.
    106      *
    107      * <p>
    108      * This form avoids superfluous object creation when the logger is disabled
    109      * for the FINEST level.
    110      * </p>
    111      *
    112      * @param format
    113      *          the format string
    114      * @param arg1
    115      *          the first argument
    116      * @param arg2
    117      *          the second argument
    118      */
    119     public void trace(String format, Object arg1, Object arg2) {
    120         if (logger.isLoggable(Level.FINEST)) {
    121             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    122             log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
    123         }
    124     }
    125
    126     /**
    127      * Log a message at level FINEST according to the specified format and
    128      * arguments.
    129      *
    130      * <p>
    131      * This form avoids superfluous object creation when the logger is disabled
    132      * for the FINEST level.
    133      * </p>
    134      *
    135      * @param format
    136      *          the format string
    137      * @param argArray
    138      *          an array of arguments
    139      */
    140     public void trace(String format, Object... argArray) {
    141         if (logger.isLoggable(Level.FINEST)) {
    142             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    143             log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
    144         }
    145     }
    146
    147     /**
    148      * Log an exception (throwable) at level FINEST with an accompanying message.
    149      *
    150      * @param msg
    151      *          the message accompanying the exception
    152      * @param t
    153      *          the exception (throwable) to log
    154      */
    155     public void trace(String msg, Throwable t) {
    156         if (logger.isLoggable(Level.FINEST)) {
    157             log(SELF, Level.FINEST, msg, t);
    158         }
    159     }
    160
    161     /**
    162      * Is this logger instance enabled for the FINE level?
    163      *
    164      * @return True if this Logger is enabled for level FINE, false otherwise.
    165      */
    166     public boolean isDebugEnabled() {
    167         return logger.isLoggable(Level.FINE);
    168     }
    169
    170     /**
    171      * Log a message object at level FINE.
    172      *
    173      * @param msg
    174      *          - the message object to be logged
    175      */
    176     public void debug(String msg) {
    177         if (logger.isLoggable(Level.FINE)) {
    178             log(SELF, Level.FINE, msg, null);
    179         }
    180     }
    181
    182     /**
    183      * Log a message at level FINE according to the specified format and argument.
    184      *
    185      * <p>
    186      * This form avoids superfluous object creation when the logger is disabled
    187      * for level FINE.
    188      * </p>
    189      *
    190      * @param format
    191      *          the format string
    192      * @param arg
    193      *          the argument
    194      */
    195     public void debug(String format, Object arg) {
    196         if (logger.isLoggable(Level.FINE)) {
    197             FormattingTuple ft = MessageFormatter.format(format, arg);
    198             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    199         }
    200     }
    201
    202     /**
    203      * Log a message at level FINE according to the specified format and
    204      * arguments.
    205      *
    206      * <p>
    207      * This form avoids superfluous object creation when the logger is disabled
    208      * for the FINE level.
    209      * </p>
    210      *
    211      * @param format
    212      *          the format string
    213      * @param arg1
    214      *          the first argument
    215      * @param arg2
    216      *          the second argument
    217      */
    218     public void debug(String format, Object arg1, Object arg2) {
    219         if (logger.isLoggable(Level.FINE)) {
    220             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    221             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    222         }
    223     }
    224
    225     /**
    226      * Log a message at level FINE according to the specified format and
    227      * arguments.
    228      *
    229      * <p>
    230      * This form avoids superfluous object creation when the logger is disabled
    231      * for the FINE level.
    232      * </p>
    233      *
    234      * @param format
    235      *          the format string
    236      * @param argArray
    237      *          an array of arguments
    238      */
    239     public void debug(String format, Object... argArray) {
    240         if (logger.isLoggable(Level.FINE)) {
    241             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    242             log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
    243         }
    244     }
    245
    246     /**
    247      * Log an exception (throwable) at level FINE with an accompanying message.
    248      *
    249      * @param msg
    250      *          the message accompanying the exception
    251      * @param t
    252      *          the exception (throwable) to log
    253      */
    254     public void debug(String msg, Throwable t) {
    255         if (logger.isLoggable(Level.FINE)) {
    256             log(SELF, Level.FINE, msg, t);
    257         }
    258     }
    259
    260     /**
    261      * Is this logger instance enabled for the INFO level?
    262      *
    263      * @return True if this Logger is enabled for the INFO level, false otherwise.
    264      */
    265     public boolean isInfoEnabled() {
    266         return logger.isLoggable(Level.INFO);
    267     }
    268
    269     /**
    270      * Log a message object at the INFO level.
    271      *
    272      * @param msg
    273      *          - the message object to be logged
    274      */
    275     public void info(String msg) {
    276         if (logger.isLoggable(Level.INFO)) {
    277             log(SELF, Level.INFO, msg, null);
    278         }
    279     }
    280
    281     /**
    282      * Log a message at level INFO according to the specified format and argument.
    283      *
    284      * <p>
    285      * This form avoids superfluous object creation when the logger is disabled
    286      * for the INFO level.
    287      * </p>
    288      *
    289      * @param format
    290      *          the format string
    291      * @param arg
    292      *          the argument
    293      */
    294     public void info(String format, Object arg) {
    295         if (logger.isLoggable(Level.INFO)) {
    296             FormattingTuple ft = MessageFormatter.format(format, arg);
    297             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    298         }
    299     }
    300
    301     /**
    302      * Log a message at the INFO level according to the specified format and
    303      * arguments.
    304      *
    305      * <p>
    306      * This form avoids superfluous object creation when the logger is disabled
    307      * for the INFO level.
    308      * </p>
    309      *
    310      * @param format
    311      *          the format string
    312      * @param arg1
    313      *          the first argument
    314      * @param arg2
    315      *          the second argument
    316      */
    317     public void info(String format, Object arg1, Object arg2) {
    318         if (logger.isLoggable(Level.INFO)) {
    319             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    320             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    321         }
    322     }
    323
    324     /**
    325      * Log a message at level INFO according to the specified format and
    326      * arguments.
    327      *
    328      * <p>
    329      * This form avoids superfluous object creation when the logger is disabled
    330      * for the INFO level.
    331      * </p>
    332      *
    333      * @param format
    334      *          the format string
    335      * @param argArray
    336      *          an array of arguments
    337      */
    338     public void info(String format, Object... argArray) {
    339         if (logger.isLoggable(Level.INFO)) {
    340             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    341             log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
    342         }
    343     }
    344
    345     /**
    346      * Log an exception (throwable) at the INFO level with an accompanying
    347      * message.
    348      *
    349      * @param msg
    350      *          the message accompanying the exception
    351      * @param t
    352      *          the exception (throwable) to log
    353      */
    354     public void info(String msg, Throwable t) {
    355         if (logger.isLoggable(Level.INFO)) {
    356             log(SELF, Level.INFO, msg, t);
    357         }
    358     }
    359
    360     /**
    361      * Is this logger instance enabled for the WARNING level?
    362      *
    363      * @return True if this Logger is enabled for the WARNING level, false
    364      *         otherwise.
    365      */
    366     public boolean isWarnEnabled() {
    367         return logger.isLoggable(Level.WARNING);
    368     }
    369
    370     /**
    371      * Log a message object at the WARNING level.
    372      *
    373      * @param msg
    374      *          - the message object to be logged
    375      */
    376     public void warn(String msg) {
    377         if (logger.isLoggable(Level.WARNING)) {
    378             log(SELF, Level.WARNING, msg, null);
    379         }
    380     }
    381
    382     /**
    383      * Log a message at the WARNING level according to the specified format and
    384      * argument.
    385      *
    386      * <p>
    387      * This form avoids superfluous object creation when the logger is disabled
    388      * for the WARNING level.
    389      * </p>
    390      *
    391      * @param format
    392      *          the format string
    393      * @param arg
    394      *          the argument
    395      */
    396     public void warn(String format, Object arg) {
    397         if (logger.isLoggable(Level.WARNING)) {
    398             FormattingTuple ft = MessageFormatter.format(format, arg);
    399             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    400         }
    401     }
    402
    403     /**
    404      * Log a message at the WARNING level according to the specified format and
    405      * arguments.
    406      *
    407      * <p>
    408      * This form avoids superfluous object creation when the logger is disabled
    409      * for the WARNING level.
    410      * </p>
    411      *
    412      * @param format
    413      *          the format string
    414      * @param arg1
    415      *          the first argument
    416      * @param arg2
    417      *          the second argument
    418      */
    419     public void warn(String format, Object arg1, Object arg2) {
    420         if (logger.isLoggable(Level.WARNING)) {
    421             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    422             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    423         }
    424     }
    425
    426     /**
    427      * Log a message at level WARNING according to the specified format and
    428      * arguments.
    429      *
    430      * <p>
    431      * This form avoids superfluous object creation when the logger is disabled
    432      * for the WARNING level.
    433      * </p>
    434      *
    435      * @param format
    436      *          the format string
    437      * @param argArray
    438      *          an array of arguments
    439      */
    440     public void warn(String format, Object... argArray) {
    441         if (logger.isLoggable(Level.WARNING)) {
    442             FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
    443             log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
    444         }
    445     }
    446
    447     /**
    448      * Log an exception (throwable) at the WARNING level with an accompanying
    449      * message.
    450      *
    451      * @param msg
    452      *          the message accompanying the exception
    453      * @param t
    454      *          the exception (throwable) to log
    455      */
    456     public void warn(String msg, Throwable t) {
    457         if (logger.isLoggable(Level.WARNING)) {
    458             log(SELF, Level.WARNING, msg, t);
    459         }
    460     }
    461
    462     /**
    463      * Is this logger instance enabled for level SEVERE?
    464      *
    465      * @return True if this Logger is enabled for level SEVERE, false otherwise.
    466      */
    467     public boolean isErrorEnabled() {
    468         return logger.isLoggable(Level.SEVERE);
    469     }
    470
    471     /**
    472      * Log a message object at the SEVERE level.
    473      *
    474      * @param msg
    475      *          - the message object to be logged
    476      */
    477     public void error(String msg) {
    478         if (logger.isLoggable(Level.SEVERE)) {
    479             log(SELF, Level.SEVERE, msg, null);
    480         }
    481     }
    482
    483     /**
    484      * Log a message at the SEVERE level according to the specified format and
    485      * argument.
    486      *
    487      * <p>
    488      * This form avoids superfluous object creation when the logger is disabled
    489      * for the SEVERE level.
    490      * </p>
    491      *
    492      * @param format
    493      *          the format string
    494      * @param arg
    495      *          the argument
    496      */
    497     public void error(String format, Object arg) {
    498         if (logger.isLoggable(Level.SEVERE)) {
    499             FormattingTuple ft = MessageFormatter.format(format, arg);
    500             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    501         }
    502     }
    503
    504     /**
    505      * Log a message at the SEVERE level according to the specified format and
    506      * arguments.
    507      *
    508      * <p>
    509      * This form avoids superfluous object creation when the logger is disabled
    510      * for the SEVERE level.
    511      * </p>
    512      *
    513      * @param format
    514      *          the format string
    515      * @param arg1
    516      *          the first argument
    517      * @param arg2
    518      *          the second argument
    519      */
    520     public void error(String format, Object arg1, Object arg2) {
    521         if (logger.isLoggable(Level.SEVERE)) {
    522             FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
    523             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    524         }
    525     }
    526
    527     /**
    528      * Log a message at level SEVERE according to the specified format and
    529      * arguments.
    530      *
    531      * <p>
    532      * This form avoids superfluous object creation when the logger is disabled
    533      * for the SEVERE level.
    534      * </p>
    535      *
    536      * @param format
    537      *          the format string
    538      * @param arguments
    539      *          an array of arguments
    540      */
    541     public void error(String format, Object... arguments) {
    542         if (logger.isLoggable(Level.SEVERE)) {
    543             FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
    544             log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
    545         }
    546     }
    547
    548     /**
    549      * Log an exception (throwable) at the SEVERE level with an accompanying
    550      * message.
    551      *
    552      * @param msg
    553      *          the message accompanying the exception
    554      * @param t
    555      *          the exception (throwable) to log
    556      */
    557     public void error(String msg, Throwable t) {
    558         if (logger.isLoggable(Level.SEVERE)) {
    559             log(SELF, Level.SEVERE, msg, t);
    560         }
    561     }
    562
    563     /**
    564      * Log the message at the specified level with the specified throwable if any.
    565      * This method creates a LogRecord and fills in caller date before calling
    566      * this instance's JDK14 logger.
    567      *
    568      * See bug report #13 for more details.
    569      *
    570      * @param level
    571      * @param msg
    572      * @param t
    573      */
    574     private void log(String callerFQCN, Level level, String msg, Throwable t) {
    575         // millis and thread are filled by the constructor
    576         LogRecord record = new LogRecord(level, msg);
    577         record.setLoggerName(getName());
    578         record.setThrown(t);
    579         // Note: parameters in record are not set because SLF4J only
    580         // supports a single formatting style
    581         fillCallerData(callerFQCN, record);
    582         logger.log(record);
    583     }
    584
    585     static String SELF = JDK14LoggerAdapter.class.getName();
    586     static String SUPER = MarkerIgnoringBase.class.getName();
    587
    588     /**
    589      * Fill in caller data if possible.
    590      *
    591      * @param record
    592      *          The record to update
    593      */
    594     final private void fillCallerData(String callerFQCN, LogRecord record) {
    595         StackTraceElement[] steArray = new Throwable().getStackTrace();
    596
    597         int selfIndex = -1;
    598         for (int i = 0; i < steArray.length; i++) {
    599             final String className = steArray[i].getClassName();
    600             if (className.equals(callerFQCN) || className.equals(SUPER)) {
    601                 selfIndex = i;
    602                 break;
    603             }
    604         }
    605
    606         int found = -1;
    607         for (int i = selfIndex + 1; i < steArray.length; i++) {
    608             final String className = steArray[i].getClassName();
    609             if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
    610                 found = i;
    611                 break;
    612             }
    613         }
    614
    615         if (found != -1) {
    616             StackTraceElement ste = steArray[found];
    617             // setting the class name has the side effect of setting
    618             // the needToInferCaller variable to false.
    619             record.setSourceClassName(ste.getClassName());
    620             record.setSourceMethodName(ste.getMethodName());
    621         }
    622     }
    623
    624     public void log(Marker marker, String callerFQCN, int level, String message, Object[] argArray, Throwable t) {
    625         Level julLevel = slf4jLevelIntToJULLevel(level);
    626         // the logger.isLoggable check avoids the unconditional
    627         // construction of location data for disabled log
    628         // statements. As of 2008-07-31, callers of this method
    629         // do not perform this check. See also
    630         // http://jira.qos.ch/browse/SLF4J-81
    631         if (logger.isLoggable(julLevel)) {
    632             log(callerFQCN, julLevel, message, t);
    633         }
    634     }
    635
    636     private Level slf4jLevelIntToJULLevel(int slf4jLevelInt) {
    637         Level julLevel;
    638         switch (slf4jLevelInt) {
    639         case LocationAwareLogger.TRACE_INT:
    640             julLevel = Level.FINEST;
    641             break;
    642         case LocationAwareLogger.DEBUG_INT:
    643             julLevel = Level.FINE;
    644             break;
    645         case LocationAwareLogger.INFO_INT:
    646             julLevel = Level.INFO;
    647             break;
    648         case LocationAwareLogger.WARN_INT:
    649             julLevel = Level.WARNING;
    650             break;
    651         case LocationAwareLogger.ERROR_INT:
    652             julLevel = Level.SEVERE;
    653             break;
    654         default:
    655             throw new IllegalStateException("Level number " + slf4jLevelInt + " is not recognized.");
    656         }
    657         return julLevel;
    658     }
    659
    660     /**
    661      * @since 1.7.15
    662      */
    663     public void log(LoggingEvent event) {
    664         Level julLevel = slf4jLevelIntToJULLevel(event.getLevel().toInt());
    665         if (logger.isLoggable(julLevel)) {
    666             LogRecord record = eventToRecord(event, julLevel);
    667             logger.log(record);
    668         }
    669     }
    670
    671     private LogRecord eventToRecord(LoggingEvent event, Level julLevel) {
    672         String format = event.getMessage();
    673         Object[] arguments = event.getArgumentArray();
    674         FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
    675         if (ft.getThrowable() != null && event.getThrowable() != null) {
    676             throw new IllegalArgumentException("both last element in argument array and last argument are of type Throwable");
    677         }
    678
    679         Throwable t = event.getThrowable();
    680         if (ft.getThrowable() != null) {
    681             t = ft.getThrowable();
    682             throw new IllegalStateException("fix above code");
    683         }
    684
    685         LogRecord record = new LogRecord(julLevel, ft.getMessage());
    686         record.setLoggerName(event.getLoggerName());
    687         record.setMillis(event.getTimeStamp());
    688         record.setSourceClassName(EventConstants.NA_SUBST);
    689         record.setSourceMethodName(EventConstants.NA_SUBST);
    690
    691         record.setThrown(t);
    692         return record;
    693     }
    694 }