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 }