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