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