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