View Javadoc

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