View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic;
15  
16  import java.io.ObjectStreamException;
17  import java.io.Serializable;
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.slf4j.LoggerFactory;
24  import org.slf4j.Marker;
25  import org.slf4j.spi.LocationAwareLogger;
26  
27  import ch.qos.logback.classic.spi.ILoggingEvent;
28  import ch.qos.logback.classic.spi.LoggerRemoteView;
29  import ch.qos.logback.classic.spi.LoggingEvent;
30  import ch.qos.logback.core.Appender;
31  import ch.qos.logback.core.CoreConstants;
32  import ch.qos.logback.core.spi.AppenderAttachable;
33  import ch.qos.logback.core.spi.AppenderAttachableImpl;
34  import ch.qos.logback.core.spi.FilterReply;
35  
36  public final class Logger implements org.slf4j.Logger, LocationAwareLogger,
37      AppenderAttachable<ILoggingEvent>, Serializable {
38  
39    /**
40     * 
41     */
42    private static final long serialVersionUID = 5454405123156820674L;
43  
44    /**
45     * The fully qualified name of this class. Used in gathering caller
46     * information.
47     */
48    public static final String FQCN = ch.qos.logback.classic.Logger.class
49        .getName();
50  
51    /**
52     * The name of this logger
53     */
54    private String name;
55  
56    // The assigned levelInt of this logger. Can be null.
57    private Level level;
58  
59    // The effective levelInt is the assigned levelInt and if null, a levelInt is
60    // inherited form a parent.
61    private int effectiveLevelInt;
62  
63    /**
64     * The parent of this category. All categories have at least one ancestor
65     * which is the root category.
66     */
67    private Logger parent;
68  
69    /**
70     * The children of this logger. A logger may have zero or more children.
71     */
72    private List<Logger> childrenList;
73  
74    /**
75     * It is assumed that once the 'aai' variable is set to a non-null value, it
76     * will never be reset to null. it is further assumed that only place where
77     * the 'aai'ariable is set is within the addAppender method. This method is
78     * synchronized on 'this' (Logger) protecting against simultaneous
79     * re-configuration of this logger (a very unlikely scenario).
80     * 
81     * <p>
82     * It is further assumed that the AppenderAttachableImpl is responsible for
83     * its internal synchronization and thread safety. Thus, we can get away with
84     * *not* synchronizing on the 'aai' (check null/ read) because
85     * <p>
86     * 1) the 'aai' variable is immutable once set to non-null
87     * <p>
88     * 2) 'aai' is getAndSet only within addAppender which is synchronized
89     * <p>
90     * 3) all the other methods check whether 'aai' is null
91     * <p>
92     * 4) AppenderAttachableImpl is thread safe
93     */
94    private transient AppenderAttachableImpl<ILoggingEvent> aai;
95    /**
96     * Additivity is set to true by default, that is children inherit the
97     * appenders of their ancestors by default. If this variable is set to
98     * <code>false</code> then the appenders located in the ancestors of this
99     * logger will not be used. However, the children of this logger will inherit
100    * its appenders, unless the children have their additivity flag set to
101    * <code>false</code> too. See the user manual for more details.
102    */
103   private boolean additive = true;
104 
105   final transient LoggerContext loggerContext;
106   // loggerRemoteView cannot be final because it may change as a consequence
107   // of changes in LoggerContext
108   LoggerRemoteView loggerRemoteView;
109 
110   Logger(String name, Logger parent, LoggerContext loggerContext) {
111     this.name = name;
112     this.parent = parent;
113     this.loggerContext = loggerContext;
114     buildRemoteView();
115   }
116 
117   public final Level getEffectiveLevel() {
118     return Level.toLevel(effectiveLevelInt);
119   }
120 
121   int getEffectiveLevelInt() {
122     return effectiveLevelInt;
123   }
124 
125   public Level getLevel() {
126     return level;
127   }
128 
129   public String getName() {
130     return name;
131   }
132 
133   private final boolean isRootLogger() {
134     // only the root logger has a null parent
135     return parent == null;
136   }
137 
138   // Logger getChildBySuffix(final String suffix) method was here and got
139   // removed.
140 
141   Logger getChildByName(final String childName) {
142     if (childrenList == null) {
143       return null;
144     } else {
145       int len = this.childrenList.size();
146       for (int i = 0; i < len; i++) {
147         final Logger childLogger_i = (Logger) childrenList.get(i);
148         final String childName_i = childLogger_i.getName();
149 
150         if (childName.equals(childName_i)) {
151           return childLogger_i;
152         }
153       }
154       // no child found
155       return null;
156     }
157   }
158 
159   public synchronized void setLevel(Level newLevel) {
160     if (level == newLevel) {
161       // nothing to do;
162       return;
163     }
164     if (newLevel == null && isRootLogger()) {
165       throw new IllegalArgumentException(
166           "The level of the root logger cannot be set to null");
167     }
168 
169     level = newLevel;
170     if (newLevel == null) {
171       effectiveLevelInt = parent.effectiveLevelInt;
172     } else {
173       effectiveLevelInt = newLevel.levelInt;
174     }
175 
176     if (childrenList != null) {
177       int len = childrenList.size();
178       for (int i = 0; i < len; i++) {
179         Logger child = (Logger) childrenList.get(i);
180         // tell child to handle parent levelInt change
181         child.handleParentLevelChange(effectiveLevelInt);
182       }
183     }
184     // inform listeners
185     loggerContext.fireOnLevelChange(this, newLevel);
186   }
187 
188   /**
189    * This method is invoked by parent logger to let this logger know that the
190    * prent's levelInt changed.
191    * 
192    * @param newParentLevelInt
193    */
194   private synchronized void handleParentLevelChange(int newParentLevelInt) {
195     // changes in the parent levelInt affect children only if their levelInt is
196     // null
197     if (level == null) {
198       effectiveLevelInt = newParentLevelInt;
199 
200       // propagate the parent levelInt change to this logger's children
201       if (childrenList != null) {
202         int len = childrenList.size();
203         for (int i = 0; i < len; i++) {
204           Logger child = (Logger) childrenList.get(i);
205           child.handleParentLevelChange(newParentLevelInt);
206         }
207       }
208     }
209   }
210 
211   /**
212    * Remove all previously added appenders from this logger instance.
213    * <p/>
214    * This is useful when re-reading configuration information.
215    */
216   public void detachAndStopAllAppenders() {
217     if (aai != null) {
218       aai.detachAndStopAllAppenders();
219     }
220   }
221 
222   public boolean detachAppender(String name) {
223     if (aai == null) {
224       return false;
225     }
226     return aai.detachAppender(name);
227   }
228 
229   // this method MUST be synchronized. See comments on 'aai' field for further
230   // details.
231   public synchronized void addAppender(Appender<ILoggingEvent> newAppender) {
232     if (aai == null) {
233       aai = new AppenderAttachableImpl<ILoggingEvent>();
234     }
235     aai.addAppender(newAppender);
236   }
237 
238   public boolean isAttached(Appender<ILoggingEvent> appender) {
239     if (aai == null) {
240       return false;
241     }
242     return aai.isAttached(appender);
243   }
244 
245   @SuppressWarnings("unchecked")
246   public Iterator<Appender<ILoggingEvent>> iteratorForAppenders() {
247     if (aai == null) {
248       return Collections.EMPTY_LIST.iterator();
249     }
250     return aai.iteratorForAppenders();
251   }
252 
253   public Appender<ILoggingEvent> getAppender(String name) {
254     if (aai == null) {
255       return null;
256     }
257     return aai.getAppender(name);
258   }
259 
260   /**
261    * Invoke all the appenders of this logger.
262    * 
263    * @param event
264    *          The event to log
265    */
266   public void callAppenders(ILoggingEvent event) {
267     int writes = 0;
268     for (Logger l = this; l != null; l = l.parent) {
269       writes += l.appendLoopOnAppenders(event);
270       if (!l.additive) {
271         break;
272       }
273     }
274     // No appenders in hierarchy
275     if (writes == 0) {
276       loggerContext.noAppenderDefinedWarning(this);
277     }
278   }
279 
280   private int appendLoopOnAppenders(ILoggingEvent event) {
281     if (aai != null) {
282       return aai.appendLoopOnAppenders(event);
283     } else {
284       return 0;
285     }
286   }
287 
288   /**
289    * Remove the appender passed as parameter form the list of appenders.
290    */
291   public boolean detachAppender(Appender<ILoggingEvent> appender) {
292     if (aai == null) {
293       return false;
294     }
295     return aai.detachAppender(appender);
296   }
297 
298   static int getSeparatorIndexOf(String name) {
299     return getSeparatorIndexOf(name, 0);
300   }
301 
302   /**
303    * Get the position of the separator character, if any, starting at position
304    * 'fromIndex'.
305    * 
306    * @param name
307    * @param fromIndex
308    * @return
309    */
310   static int getSeparatorIndexOf(String name, int fromIndex) {
311     int i = name.indexOf(CoreConstants.DOT, fromIndex);
312     if (i != -1) {
313       return i;
314     } else {
315       return name.indexOf(CoreConstants.DOLLAR, fromIndex);
316     }
317   }
318 
319   /**
320    * Create a child of this logger by suffix, that is, the part of the name
321    * extending this logger. For example, if this logger is named "x.y" and the
322    * lastPart is "z", then the created child logger will be named "x.y.z".
323    * 
324    * <p>
325    * IMPORTANT: Calls to this method must be within a synchronized block on this
326    * logger.
327    * 
328    * @param lastPart
329    *          the suffix (i.e. last part) of the child logger name. This
330    *          parameter may not include dots, i.e. the logger separator
331    *          character.
332    * @return
333    */
334   Logger createChildByLastNamePart(final String lastPart) {
335     int i_index = getSeparatorIndexOf(lastPart);
336     if (i_index != -1) {
337       throw new IllegalArgumentException("Child name [" + lastPart
338           + " passed as parameter, may not include [" + CoreConstants.DOT + "]");
339     }
340 
341     if (childrenList == null) {
342       childrenList = new ArrayList<Logger>();
343     }
344     Logger childLogger;
345     if (this.isRootLogger()) {
346       childLogger = new Logger(lastPart, this, this.loggerContext);
347     } else {
348       childLogger = new Logger(name + CoreConstants.DOT + lastPart, this,
349           this.loggerContext);
350     }
351     childrenList.add(childLogger);
352     childLogger.effectiveLevelInt = this.effectiveLevelInt;
353     return childLogger;
354   }
355 
356   private void localLevelReset() {
357     effectiveLevelInt = Level.DEBUG_INT;
358     if (isRootLogger()) {
359       level = Level.DEBUG;
360     } else {
361       level = null;
362     }
363   }
364 
365   void recursiveReset() {
366     detachAndStopAllAppenders();
367     localLevelReset();
368     additive = true;
369     if (childrenList == null) {
370       return;
371     }
372     for (Logger childLogger : childrenList) {
373       childLogger.recursiveReset();
374     }
375   }
376 
377   /**
378    * The default size of child list arrays. The JDK 1.5 default is 10. We use a
379    * smaller value to save a little space.
380    */
381   static private final int DEFAULT_CHILD_ARRAY_SIZE = 5;
382 
383   Logger createChildByName(final String childName) {
384     int i_index = getSeparatorIndexOf(childName, this.name.length() + 1);
385     if (i_index != -1) {
386       throw new IllegalArgumentException("For logger [" + this.name
387           + "] child name [" + childName
388           + " passed as parameter, may not include '.' after index"
389           + (this.name.length() + 1));
390     }
391 
392     if (childrenList == null) {
393       childrenList = new ArrayList<Logger>(DEFAULT_CHILD_ARRAY_SIZE);
394     }
395     Logger childLogger;
396     childLogger = new Logger(childName, this, this.loggerContext);
397     childrenList.add(childLogger);
398     childLogger.effectiveLevelInt = this.effectiveLevelInt;
399     return childLogger;
400   }
401 
402   /**
403    * The next methods are not merged into one because of the time we gain by not
404    * creating a new Object[] with the params. This reduces the cost of not
405    * logging by about 20 nanoseconds.
406    */
407 
408   private final void filterAndLog_0_Or3Plus(final String localFQCN,
409       final Marker marker, final Level level, final String msg,
410       final Object[] params, final Throwable t) {
411 
412     final FilterReply decision = loggerContext
413         .getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg,
414             params, t);
415 
416     if (decision == FilterReply.NEUTRAL) {
417       if (effectiveLevelInt > level.levelInt) {
418         return;
419       }
420     } else if (decision == FilterReply.DENY) {
421       return;
422     }
423 
424     buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
425   }
426 
427   private final void filterAndLog_1(final String localFQCN,
428       final Marker marker, final Level level, final String msg,
429       final Object param, final Throwable t) {
430 
431     final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(
432         marker, this, level, msg, param, t);
433 
434     if (decision == FilterReply.NEUTRAL) {
435       if (effectiveLevelInt > level.levelInt) {
436         return;
437       }
438     } else if (decision == FilterReply.DENY) {
439       return;
440     }
441 
442     buildLoggingEventAndAppend(localFQCN, marker, level, msg,
443         new Object[] { param }, t);
444   }
445 
446   private final void filterAndLog_2(final String localFQCN,
447       final Marker marker, final Level level, final String msg,
448       final Object param1, final Object param2, final Throwable t) {
449 
450     final FilterReply decision = loggerContext.getTurboFilterChainDecision_2(
451         marker, this, level, msg, param1, param2, t);
452 
453     if (decision == FilterReply.NEUTRAL) {
454       if (effectiveLevelInt > level.levelInt) {
455         return;
456       }
457     } else if (decision == FilterReply.DENY) {
458       return;
459     }
460 
461     buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] {
462         param1, param2 }, t);
463   }
464 
465   private void buildLoggingEventAndAppend(final String localFQCN,
466       final Marker marker, final Level level, final String msg,
467       final Object[] params, final Throwable t) {
468     LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
469     le.setMarker(marker);
470     callAppenders(le);
471   }
472 
473   public void trace(String msg) {
474     filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, null);
475   }
476 
477   public final void trace(String format, Object arg) {
478     filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null);
479   }
480 
481   public void trace(String format, Object arg1, Object arg2) {
482     filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null);
483   }
484 
485   public void trace(String format, Object[] argArray) {
486     filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null);
487   }
488 
489   public void trace(String msg, Throwable t) {
490     filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t);
491   }
492 
493   public final void trace(Marker marker, String msg) {
494     filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, null);
495   }
496 
497   public void trace(Marker marker, String format, Object arg) {
498     filterAndLog_1(FQCN, marker, Level.TRACE, format, arg, null);
499   }
500 
501   public void trace(Marker marker, String format, Object arg1, Object arg2) {
502     filterAndLog_2(FQCN, marker, Level.TRACE, format, arg1, arg2, null);
503   }
504 
505   public void trace(Marker marker, String format, Object[] argArray) {
506     filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, format, argArray, null);
507   }
508 
509   public void trace(Marker marker, String msg, Throwable t) {
510     filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, t);
511   }
512 
513   final public boolean isDebugEnabled() {
514     return isDebugEnabled(null);
515   }
516 
517   final public boolean isDebugEnabled(Marker marker) {
518     final FilterReply decision = callTurboFilters(marker, Level.DEBUG);
519     if (decision == FilterReply.NEUTRAL) {
520       return effectiveLevelInt <= Level.DEBUG_INT;
521     } else if (decision == FilterReply.DENY) {
522       return false;
523     } else if (decision == FilterReply.ACCEPT) {
524       return true;
525     } else {
526       throw new IllegalStateException("Unknown FilterReply value: " + decision);
527     }
528   }
529 
530   final public void debug(String msg) {
531     filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, null);
532   }
533 
534   final public void debug(String format, Object arg) {
535     filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null);
536   }
537 
538   final public void debug(String format, Object arg1, Object arg2) {
539     filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null);
540   }
541 
542   final public void debug(String format, Object[] argArray) {
543     filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null);
544   }
545 
546   public void debug(String msg, Throwable t) {
547     filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t);
548   }
549 
550   public final void debug(Marker marker, String msg) {
551     filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, null);
552   }
553 
554   public void debug(Marker marker, String format, Object arg) {
555     filterAndLog_1(FQCN, marker, Level.DEBUG, format, arg, null);
556   }
557 
558   public void debug(Marker marker, String format, Object arg1, Object arg2) {
559     filterAndLog_2(FQCN, marker, Level.DEBUG, format, arg1, arg2, null);
560   }
561 
562   public void debug(Marker marker, String format, Object[] argArray) {
563     filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, format, argArray, null);
564   }
565 
566   public void debug(Marker marker, String msg, Throwable t) {
567     filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, t);
568   }
569 
570   public void error(String msg) {
571     filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, null);
572   }
573 
574   public void error(String format, Object arg) {
575     filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null);
576   }
577 
578   public void error(String format, Object arg1, Object arg2) {
579     filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null);
580   }
581 
582   public void error(String format, Object[] argArray) {
583     filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null);
584   }
585 
586   public void error(String msg, Throwable t) {
587     filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t);
588   }
589 
590   public void error(Marker marker, String msg) {
591     filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, null);
592   }
593 
594   public void error(Marker marker, String format, Object arg) {
595     filterAndLog_1(FQCN, marker, Level.ERROR, format, arg, null);
596   }
597 
598   public void error(Marker marker, String format, Object arg1, Object arg2) {
599     filterAndLog_2(FQCN, marker, Level.ERROR, format, arg1, arg2, null);
600   }
601 
602   public void error(Marker marker, String format, Object[] argArray) {
603     filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, format, argArray, null);
604   }
605 
606   public void error(Marker marker, String msg, Throwable t) {
607     filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, t);
608   }
609 
610   public boolean isInfoEnabled() {
611     return isInfoEnabled(null);
612   }
613 
614   public boolean isInfoEnabled(Marker marker) {
615     FilterReply decision = callTurboFilters(marker, Level.INFO);
616     if (decision == FilterReply.NEUTRAL) {
617       return effectiveLevelInt <= Level.INFO_INT;
618     } else if (decision == FilterReply.DENY) {
619       return false;
620     } else if (decision == FilterReply.ACCEPT) {
621       return true;
622     } else {
623       throw new IllegalStateException("Unknown FilterReply value: " + decision);
624     }
625   }
626 
627   public void info(String msg) {
628     filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
629   }
630 
631   public void info(String format, Object arg) {
632     filterAndLog_1(FQCN, null, Level.INFO, format, arg, null);
633   }
634 
635   public void info(String format, Object arg1, Object arg2) {
636     filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null);
637   }
638 
639   public void info(String format, Object[] argArray) {
640     filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null);
641   }
642 
643   public void info(String msg, Throwable t) {
644     filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t);
645   }
646 
647   public void info(Marker marker, String msg) {
648     filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, null);
649   }
650 
651   public void info(Marker marker, String format, Object arg) {
652     filterAndLog_1(FQCN, marker, Level.INFO, format, arg, null);
653   }
654 
655   public void info(Marker marker, String format, Object arg1, Object arg2) {
656     filterAndLog_2(FQCN, marker, Level.INFO, format, arg1, arg2, null);
657   }
658 
659   public void info(Marker marker, String format, Object[] argArray) {
660     filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, format, argArray, null);
661   }
662 
663   public void info(Marker marker, String msg, Throwable t) {
664     filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, t);
665   }
666 
667   public final boolean isTraceEnabled() {
668     return isTraceEnabled(null);
669   }
670 
671   public boolean isTraceEnabled(Marker marker) {
672     final FilterReply decision = callTurboFilters(marker, Level.TRACE);
673     if (decision == FilterReply.NEUTRAL) {
674       return effectiveLevelInt <= Level.TRACE_INT;
675     } else if (decision == FilterReply.DENY) {
676       return false;
677     } else if (decision == FilterReply.ACCEPT) {
678       return true;
679     } else {
680       throw new IllegalStateException("Unknown FilterReply value: " + decision);
681     }
682   }
683 
684   public final boolean isErrorEnabled() {
685     return isErrorEnabled(null);
686   }
687 
688   public boolean isErrorEnabled(Marker marker) {
689     FilterReply decision = callTurboFilters(marker, Level.ERROR);
690     if (decision == FilterReply.NEUTRAL) {
691       return effectiveLevelInt <= Level.ERROR_INT;
692     } else if (decision == FilterReply.DENY) {
693       return false;
694     } else if (decision == FilterReply.ACCEPT) {
695       return true;
696     } else {
697       throw new IllegalStateException("Unknown FilterReply value: " + decision);
698     }
699   }
700 
701   public boolean isWarnEnabled() {
702     return isWarnEnabled(null);
703   }
704 
705   public boolean isWarnEnabled(Marker marker) {
706     FilterReply decision = callTurboFilters(marker, Level.WARN);
707     if (decision == FilterReply.NEUTRAL) {
708       return effectiveLevelInt <= Level.WARN_INT;
709     } else if (decision == FilterReply.DENY) {
710       return false;
711     } else if (decision == FilterReply.ACCEPT) {
712       return true;
713     } else {
714       throw new IllegalStateException("Unknown FilterReply value: " + decision);
715     }
716 
717   }
718 
719   public boolean isEnabledFor(Marker marker, Level level) {
720     FilterReply decision = callTurboFilters(marker, level);
721     if (decision == FilterReply.NEUTRAL) {
722       return effectiveLevelInt <= level.levelInt;
723     } else if (decision == FilterReply.DENY) {
724       return false;
725     } else if (decision == FilterReply.ACCEPT) {
726       return true;
727     } else {
728       throw new IllegalStateException("Unknown FilterReply value: " + decision);
729     }
730   }
731 
732   public boolean isEnabledFor(Level level) {
733     return isEnabledFor(null, level);
734   }
735 
736   public void warn(String msg) {
737     filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, null);
738   }
739 
740   public void warn(String msg, Throwable t) {
741     filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t);
742   }
743 
744   public void warn(String format, Object arg) {
745     filterAndLog_1(FQCN, null, Level.WARN, format, arg, null);
746   }
747 
748   public void warn(String format, Object arg1, Object arg2) {
749     filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null);
750   }
751 
752   public void warn(String format, Object[] argArray) {
753     filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null);
754   }
755 
756   public void warn(Marker marker, String msg) {
757     filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, null);
758   }
759 
760   public void warn(Marker marker, String format, Object arg) {
761     filterAndLog_1(FQCN, marker, Level.WARN, format, arg, null);
762   }
763 
764   public void warn(Marker marker, String format, Object[] argArray) {
765     filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, format, argArray, null);
766   }
767 
768   public void warn(Marker marker, String format, Object arg1, Object arg2) {
769     filterAndLog_2(FQCN, marker, Level.WARN, format, arg1, arg2, null);
770   }
771 
772   public void warn(Marker marker, String msg, Throwable t) {
773     filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, t);
774   }
775 
776   public boolean isAdditive() {
777     return additive;
778   }
779 
780   public void setAdditive(boolean additive) {
781     this.additive = additive;
782   }
783 
784   public String toString() {
785     return "Logger[" + name + "]";
786   }
787 
788   /**
789    * Method that calls the attached TurboFilter objects based on the logger and
790    * the level.
791    * 
792    * It is used by isYYYEnabled() methods.
793    * 
794    * It returns the typical FilterReply values: ACCEPT, NEUTRAL or DENY.
795    * 
796    * @param level
797    * @return the reply given by the TurboFilters
798    */
799   private FilterReply callTurboFilters(Marker marker, Level level) {
800     return loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this,
801         level, null, null, null);
802   }
803 
804   /**
805    * Return the context for this logger.
806    * 
807    * @return the context
808    */
809   public LoggerContext getLoggerContext() {
810     return loggerContext;
811   }
812 
813   public LoggerRemoteView getLoggerRemoteView() {
814     return loggerRemoteView;
815   }
816 
817   void buildRemoteView() {
818     this.loggerRemoteView = new LoggerRemoteView(name, loggerContext);
819   }
820 
821   public void log(Marker marker, String fqcn, int levelInt, String message,
822       Object[] argArray, Throwable t) {
823     Level level = null;
824     switch (levelInt) {
825     case LocationAwareLogger.TRACE_INT:
826       level = Level.TRACE;
827       break;
828     case LocationAwareLogger.DEBUG_INT:
829       level = Level.DEBUG;
830       break;
831     case LocationAwareLogger.INFO_INT:
832       level = Level.INFO;
833       break;
834     case LocationAwareLogger.WARN_INT:
835       level = Level.WARN;
836       break;
837     case LocationAwareLogger.ERROR_INT:
838       level = Level.ERROR;
839       break;
840     default:
841       throw new IllegalArgumentException(levelInt + " not a valid level value");
842     }
843     filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
844   }
845 
846   /**
847    * After serialization, the logger instance does not know its LoggerContext.
848    * The best we can do here, is to return a logger with the same name as
849    * generated by LoggerFactory.
850    * 
851    * @return Logger instance with the same name
852    * @throws ObjectStreamException
853    */
854   protected Object readResolve() throws ObjectStreamException {
855     return LoggerFactory.getLogger(getName());
856   }
857 }