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