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