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