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 */
25package org.slf4j.impl;
26
27import java.io.Serializable;
28
29import org.apache.log4j.Level;
30import org.slf4j.Logger;
31import org.slf4j.Marker;
32import org.slf4j.helpers.FormattingTuple;
33import org.slf4j.helpers.MarkerIgnoringBase;
34import org.slf4j.helpers.MessageFormatter;
35import org.slf4j.spi.LocationAwareLogger;
36
37/**
38 * A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in
39 * conforming to the {@link Logger} interface.
40 *
41 * <p>
42 * Note that the logging levels mentioned in this class refer to those defined
43 * in the <a
44 * href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Level.html">
45 * <code>org.apache.log4j.Level</code></a> class.
46 *
47 * <p>
48 * The TRACE level was introduced in log4j version 1.2.12. In order to avoid
49 * crashing the host application, in the case the log4j version in use predates
50 * 1.2.12, the TRACE level will be mapped as DEBUG. See also <a
51 * href="http://bugzilla.slf4j.org/show_bug.cgi?id=68">bug 68</a>.
52 *
53 * @author Ceki G&uuml;lc&uuml;
54 */
55public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable {
56
57    private static final long serialVersionUID = 6182834493563598289L;
58
59    final transient org.apache.log4j.Logger logger;
60
61    /**
62     * Following the pattern discussed in pages 162 through 168 of "The complete
63     * log4j manual".
64     */
65    final static String FQCN = Log4jLoggerAdapter.class.getName();
66
67    // Does the log4j version in use recognize the TRACE level?
68    // The trace level was introduced in log4j 1.2.12.
69    final boolean traceCapable;
70
71    // WARN: Log4jLoggerAdapter constructor should have only package access so
72    // that
73    // only Log4jLoggerFactory be able to create one.
74    Log4jLoggerAdapter(org.apache.log4j.Logger logger) {
75        this.logger = logger;
76        this.name = logger.getName();
77        traceCapable = isTraceCapable();
78    }
79
80    private boolean isTraceCapable() {
81        try {
82            logger.isTraceEnabled();
83            return true;
84        } catch (NoSuchMethodError e) {
85            return false;
86        }
87    }
88
89    /**
90     * Is this logger instance enabled for the TRACE level?
91     *
92     * @return True if this Logger is enabled for level TRACE, false otherwise.
93     */
94    public boolean isTraceEnabled() {
95        if (traceCapable) {
96            return logger.isTraceEnabled();
97        } else {
98            return logger.isDebugEnabled();
99        }
100    }
101
102    /**
103     * Log a message object at level TRACE.
104     *
105     * @param msg
106     *          - the message object to be logged
107     */
108    public void trace(String msg) {
109        logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null);
110    }
111
112    /**
113     * Log a message at level TRACE according to the specified format and
114     * argument.
115     *
116     * <p>
117     * This form avoids superfluous object creation when the logger is disabled
118     * for level TRACE.
119     * </p>
120     *
121     * @param format
122     *          the format string
123     * @param arg
124     *          the argument
125     */
126    public void trace(String format, Object arg) {
127        if (isTraceEnabled()) {
128            FormattingTuple ft = MessageFormatter.format(format, arg);
129            logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft.getMessage(), ft.getThrowable());
130        }
131    }
132
133    /**
134     * Log a message at level TRACE according to the specified format and
135     * arguments.
136     *
137     * <p>
138     * This form avoids superfluous object creation when the logger is disabled
139     * for the TRACE level.
140     * </p>
141     *
142     * @param format
143     *          the format string
144     * @param arg1
145     *          the first argument
146     * @param arg2
147     *          the second argument
148     */
149    public void trace(String format, Object arg1, Object arg2) {
150        if (isTraceEnabled()) {
151            FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
152            logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft.getMessage(), ft.getThrowable());
153        }
154    }
155
156    /**
157     * Log a message at level TRACE according to the specified format and
158     * arguments.
159     *
160     * <p>
161     * This form avoids superfluous object creation when the logger is disabled
162     * for the TRACE level.
163     * </p>
164     *
165     * @param format
166     *          the format string
167     * @param arguments
168     *          an array of arguments
169     */
170    public void trace(String format, Object... arguments) {
171        if (isTraceEnabled()) {
172            FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
173            logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft.getMessage(), ft.getThrowable());
174        }
175    }
176
177    /**
178     * Log an exception (throwable) at level TRACE with an accompanying message.
179     *
180     * @param msg
181     *          the message accompanying the exception
182     * @param t
183     *          the exception (throwable) to log
184     */
185    public void trace(String msg, Throwable t) {
186        logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t);
187    }
188
189    /**
190     * Is this logger instance enabled for the DEBUG level?
191     *
192     * @return True if this Logger is enabled for level DEBUG, false otherwise.
193     */
194    public boolean isDebugEnabled() {
195        return logger.isDebugEnabled();
196    }
197
198    /**
199     * Log a message object at level DEBUG.
200     *
201     * @param msg
202     *          - the message object to be logged
203     */
204    public void debug(String msg) {
205        logger.log(FQCN, Level.DEBUG, msg, null);
206    }
207
208    /**
209     * Log a message at level DEBUG according to the specified format and
210     * argument.
211     *
212     * <p>
213     * This form avoids superfluous object creation when the logger is disabled
214     * for level DEBUG.
215     * </p>
216     *
217     * @param format
218     *          the format string
219     * @param arg
220     *          the argument
221     */
222    public void debug(String format, Object arg) {
223        if (logger.isDebugEnabled()) {
224            FormattingTuple ft = MessageFormatter.format(format, arg);
225            logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
226        }
227    }
228
229    /**
230     * Log a message at level DEBUG according to the specified format and
231     * arguments.
232     *
233     * <p>
234     * This form avoids superfluous object creation when the logger is disabled
235     * for the DEBUG level.
236     * </p>
237     *
238     * @param format
239     *          the format string
240     * @param arg1
241     *          the first argument
242     * @param arg2
243     *          the second argument
244     */
245    public void debug(String format, Object arg1, Object arg2) {
246        if (logger.isDebugEnabled()) {
247            FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
248            logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
249        }
250    }
251
252    /**
253     * Log a message at level DEBUG according to the specified format and
254     * arguments.
255     *
256     * <p>
257     * This form avoids superfluous object creation when the logger is disabled
258     * for the DEBUG level.
259     * </p>
260     *
261     * @param format
262     *          the format string
263     * @param arguments an array of arguments
264     */
265    public void debug(String format, Object... arguments) {
266        if (logger.isDebugEnabled()) {
267            FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
268            logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
269        }
270    }
271
272    /**
273     * Log an exception (throwable) at level DEBUG with an accompanying message.
274     *
275     * @param msg
276     *          the message accompanying the exception
277     * @param t
278     *          the exception (throwable) to log
279     */
280    public void debug(String msg, Throwable t) {
281        logger.log(FQCN, Level.DEBUG, msg, t);
282    }
283
284    /**
285     * Is this logger instance enabled for the INFO level?
286     *
287     * @return True if this Logger is enabled for the INFO level, false otherwise.
288     */
289    public boolean isInfoEnabled() {
290        return logger.isInfoEnabled();
291    }
292
293    /**
294     * Log a message object at the INFO level.
295     *
296     * @param msg
297     *          - the message object to be logged
298     */
299    public void info(String msg) {
300        logger.log(FQCN, Level.INFO, msg, null);
301    }
302
303    /**
304     * Log a message at level INFO according to the specified format and argument.
305     *
306     * <p>
307     * This form avoids superfluous object creation when the logger is disabled
308     * for the INFO level.
309     * </p>
310     *
311     * @param format
312     *          the format string
313     * @param arg
314     *          the argument
315     */
316    public void info(String format, Object arg) {
317        if (logger.isInfoEnabled()) {
318            FormattingTuple ft = MessageFormatter.format(format, arg);
319            logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
320        }
321    }
322
323    /**
324     * Log a message at the INFO level 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 arg1
335     *          the first argument
336     * @param arg2
337     *          the second argument
338     */
339    public void info(String format, Object arg1, Object arg2) {
340        if (logger.isInfoEnabled()) {
341            FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
342            logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
343        }
344    }
345
346    /**
347     * Log a message at level INFO according to the specified format and
348     * arguments.
349     *
350     * <p>
351     * This form avoids superfluous object creation when the logger is disabled
352     * for the INFO level.
353     * </p>
354     *
355     * @param format
356     *          the format string
357     * @param argArray
358     *          an array of arguments
359     */
360    public void info(String format, Object... argArray) {
361        if (logger.isInfoEnabled()) {
362            FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
363            logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
364        }
365    }
366
367    /**
368     * Log an exception (throwable) at the INFO level with an accompanying
369     * message.
370     *
371     * @param msg
372     *          the message accompanying the exception
373     * @param t
374     *          the exception (throwable) to log
375     */
376    public void info(String msg, Throwable t) {
377        logger.log(FQCN, Level.INFO, msg, t);
378    }
379
380    /**
381     * Is this logger instance enabled for the WARN level?
382     *
383     * @return True if this Logger is enabled for the WARN level, false otherwise.
384     */
385    public boolean isWarnEnabled() {
386        return logger.isEnabledFor(Level.WARN);
387    }
388
389    /**
390     * Log a message object at the WARN level.
391     *
392     * @param msg
393     *          - the message object to be logged
394     */
395    public void warn(String msg) {
396        logger.log(FQCN, Level.WARN, msg, null);
397    }
398
399    /**
400     * Log a message at the WARN level according to the specified format and
401     * argument.
402     *
403     * <p>
404     * This form avoids superfluous object creation when the logger is disabled
405     * for the WARN level.
406     * </p>
407     *
408     * @param format
409     *          the format string
410     * @param arg
411     *          the argument
412     */
413    public void warn(String format, Object arg) {
414        if (logger.isEnabledFor(Level.WARN)) {
415            FormattingTuple ft = MessageFormatter.format(format, arg);
416            logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
417        }
418    }
419
420    /**
421     * Log a message at the WARN level according to the specified format and
422     * arguments.
423     *
424     * <p>
425     * This form avoids superfluous object creation when the logger is disabled
426     * for the WARN level.
427     * </p>
428     *
429     * @param format
430     *          the format string
431     * @param arg1
432     *          the first argument
433     * @param arg2
434     *          the second argument
435     */
436    public void warn(String format, Object arg1, Object arg2) {
437        if (logger.isEnabledFor(Level.WARN)) {
438            FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
439            logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
440        }
441    }
442
443    /**
444     * Log a message at level WARN according to the specified format and
445     * arguments.
446     *
447     * <p>
448     * This form avoids superfluous object creation when the logger is disabled
449     * for the WARN level.
450     * </p>
451     *
452     * @param format
453     *          the format string
454     * @param argArray
455     *          an array of arguments
456     */
457    public void warn(String format, Object... argArray) {
458        if (logger.isEnabledFor(Level.WARN)) {
459            FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
460            logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
461        }
462    }
463
464    /**
465     * Log an exception (throwable) at the WARN level with an accompanying
466     * message.
467     *
468     * @param msg
469     *          the message accompanying the exception
470     * @param t
471     *          the exception (throwable) to log
472     */
473    public void warn(String msg, Throwable t) {
474        logger.log(FQCN, Level.WARN, msg, t);
475    }
476
477    /**
478     * Is this logger instance enabled for level ERROR?
479     *
480     * @return True if this Logger is enabled for level ERROR, false otherwise.
481     */
482    public boolean isErrorEnabled() {
483        return logger.isEnabledFor(Level.ERROR);
484    }
485
486    /**
487     * Log a message object at the ERROR level.
488     *
489     * @param msg
490     *          - the message object to be logged
491     */
492    public void error(String msg) {
493        logger.log(FQCN, Level.ERROR, msg, null);
494    }
495
496    /**
497     * Log a message at the ERROR level according to the specified format and
498     * argument.
499     *
500     * <p>
501     * This form avoids superfluous object creation when the logger is disabled
502     * for the ERROR level.
503     * </p>
504     *
505     * @param format
506     *          the format string
507     * @param arg
508     *          the argument
509     */
510    public void error(String format, Object arg) {
511        if (logger.isEnabledFor(Level.ERROR)) {
512            FormattingTuple ft = MessageFormatter.format(format, arg);
513            logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
514        }
515    }
516
517    /**
518     * Log a message at the ERROR level according to the specified format and
519     * arguments.
520     *
521     * <p>
522     * This form avoids superfluous object creation when the logger is disabled
523     * for the ERROR level.
524     * </p>
525     *
526     * @param format
527     *          the format string
528     * @param arg1
529     *          the first argument
530     * @param arg2
531     *          the second argument
532     */
533    public void error(String format, Object arg1, Object arg2) {
534        if (logger.isEnabledFor(Level.ERROR)) {
535            FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
536            logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
537        }
538    }
539
540    /**
541     * Log a message at level ERROR according to the specified format and
542     * arguments.
543     *
544     * <p>
545     * This form avoids superfluous object creation when the logger is disabled
546     * for the ERROR level.
547     * </p>
548     *
549     * @param format
550     *          the format string
551     * @param argArray
552     *          an array of arguments
553     */
554    public void error(String format, Object... argArray) {
555        if (logger.isEnabledFor(Level.ERROR)) {
556            FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
557            logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
558        }
559    }
560
561    /**
562     * Log an exception (throwable) at the ERROR level with an accompanying
563     * message.
564     *
565     * @param msg
566     *          the message accompanying the exception
567     * @param t
568     *          the exception (throwable) to log
569     */
570    public void error(String msg, Throwable t) {
571        logger.log(FQCN, Level.ERROR, msg, t);
572    }
573
574    public void log(Marker marker, String callerFQCN, int level, String msg, Object[] argArray, Throwable t) {
575        Level log4jLevel;
576        switch (level) {
577        case LocationAwareLogger.TRACE_INT:
578            log4jLevel = traceCapable ? Level.TRACE : Level.DEBUG;
579            break;
580        case LocationAwareLogger.DEBUG_INT:
581            log4jLevel = Level.DEBUG;
582            break;
583        case LocationAwareLogger.INFO_INT:
584            log4jLevel = Level.INFO;
585            break;
586        case LocationAwareLogger.WARN_INT:
587            log4jLevel = Level.WARN;
588            break;
589        case LocationAwareLogger.ERROR_INT:
590            log4jLevel = Level.ERROR;
591            break;
592        default:
593            throw new IllegalStateException("Level number " + level + " is not recognized.");
594        }
595        logger.log(callerFQCN, log4jLevel, msg, t);
596    }
597
598}
599