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