1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, 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.Collections;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.concurrent.CopyOnWriteArrayList;
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.LoggingEvent;
29 import ch.qos.logback.classic.util.LoggerNameUtil;
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, AppenderAttachable<ILoggingEvent>, Serializable {
37
38     private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
39
40     /**
41      * The fully qualified name of this class. Used in gathering caller
42      * information.
43      */

44     public static final String FQCN = ch.qos.logback.classic.Logger.class.getName();
45
46     /**
47      * The name of this logger
48      */

49     private String name;
50
51     // The assigned levelInt of this logger. Can be null.
52     transient private Level level;
53
54     // The effective levelInt is the assigned levelInt and if null, a levelInt is
55     // inherited form a parent.
56     transient private int effectiveLevelInt;
57
58     /**
59      * The parent of this category. All categories have at least one ancestor
60      * which is the root category.
61      */

62     transient private Logger parent;
63
64     /**
65      * The children of this logger. A logger may have zero or more children.
66      */

67     transient private List<Logger> childrenList;
68
69     /**
70      * It is assumed that once the 'aai' variable is set to a non-null value, it
71      * will never be reset to null. it is further assumed that only place where
72      * the 'aai'ariable is set is within the addAppender method. This method is
73      * synchronized on 'this' (Logger) protecting against simultaneous
74      * re-configuration of this logger (a very unlikely scenario).
75      * 
76      * <p>
77      * It is further assumed that the AppenderAttachableImpl is responsible for
78      * its internal synchronization and thread safety. Thus, we can get away with
79      * *not* synchronizing on the 'aai' (check null/ read) because
80      * <p>
81      * 1) the 'aai' variable is immutable once set to non-null
82      * <p>
83      * 2) 'aai' is getAndSet only within addAppender which is synchronized
84      * <p>
85      * 3) all the other methods check whether 'aai' is null
86      * <p>
87      * 4) AppenderAttachableImpl is thread safe
88      */

89     transient private AppenderAttachableImpl<ILoggingEvent> aai;
90     /**
91      * Additivity is set to true by default, that is children inherit the
92      * appenders of their ancestors by default. If this variable is set to
93      * <code>false</code> then the appenders located in the ancestors of this
94      * logger will not be used. However, the children of this logger will inherit
95      * its appenders, unless the children have their additivity flag set to
96      * <code>false</code> too. See the user manual for more details.
97      */

98     transient private boolean additive = true;
99
100     final transient LoggerContext loggerContext;
101
102     Logger(String name, Logger parent, LoggerContext loggerContext) {
103         this.name = name;
104         this.parent = parent;
105         this.loggerContext = loggerContext;
106     }
107
108     public Level getEffectiveLevel() {
109         return Level.toLevel(effectiveLevelInt);
110     }
111
112     int getEffectiveLevelInt() {
113         return effectiveLevelInt;
114     }
115
116     public Level getLevel() {
117         return level;
118     }
119
120     public String getName() {
121         return name;
122     }
123
124     private boolean isRootLogger() {
125         // only the root logger has a null parent
126         return parent == null;
127     }
128
129     Logger getChildByName(final String childName) {
130         if (childrenList == null) {
131             return null;
132         } else {
133             int len = this.childrenList.size();
134             for (int i = 0; i < len; i++) {
135                 final Logger childLogger_i = (Logger) childrenList.get(i);
136                 final String childName_i = childLogger_i.getName();
137
138                 if (childName.equals(childName_i)) {
139                     return childLogger_i;
140                 }
141             }
142             // no child found
143             return null;
144         }
145     }
146
147     public synchronized void setLevel(Level newLevel) {
148         if (level == newLevel) {
149             // nothing to do;
150             return;
151         }
152         if (newLevel == null && isRootLogger()) {
153             throw new IllegalArgumentException("The level of the root logger cannot be set to null");
154         }
155
156         level = newLevel;
157         if (newLevel == null) {
158             effectiveLevelInt = parent.effectiveLevelInt;
159             newLevel = parent.getEffectiveLevel();
160         } else {
161             effectiveLevelInt = newLevel.levelInt;
162         }
163
164         if (childrenList != null) {
165             int len = childrenList.size();
166             for (int i = 0; i < len; i++) {
167                 Logger child = (Logger) childrenList.get(i);
168                 // tell child to handle parent levelInt change
169                 child.handleParentLevelChange(effectiveLevelInt);
170             }
171         }
172         // inform listeners
173         loggerContext.fireOnLevelChange(this, newLevel);
174     }
175
176     /**
177      * This method is invoked by parent logger to let this logger know that the
178      * prent's levelInt changed.
179      * 
180      * @param newParentLevelInt
181      */

182     private synchronized void handleParentLevelChange(int newParentLevelInt) {
183         // changes in the parent levelInt affect children only if their levelInt is
184         // null
185         if (level == null) {
186             effectiveLevelInt = newParentLevelInt;
187
188             // propagate the parent levelInt change to this logger's children
189             if (childrenList != null) {
190                 int len = childrenList.size();
191                 for (int i = 0; i < len; i++) {
192                     Logger child = (Logger) childrenList.get(i);
193                     child.handleParentLevelChange(newParentLevelInt);
194                 }
195             }
196         }
197     }
198
199     /**
200      * Remove all previously added appenders from this logger instance.
201      * <p/>
202      * This 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<ILoggingEvent> newAppender) {
220         if (aai == null) {
221             aai = new AppenderAttachableImpl<ILoggingEvent>();
222         }
223         aai.addAppender(newAppender);
224     }
225
226     public boolean isAttached(Appender<ILoggingEvent> appender) {
227         if (aai == null) {
228             return false;
229         }
230         return aai.isAttached(appender);
231     }
232
233     @SuppressWarnings("unchecked")
234     public Iterator<Appender<ILoggingEvent>> iteratorForAppenders() {
235         if (aai == null) {
236             return Collections.EMPTY_LIST.iterator();
237         }
238         return aai.iteratorForAppenders();
239     }
240
241     public Appender<ILoggingEvent> 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(ILoggingEvent 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(ILoggingEvent 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<ILoggingEvent> 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>
292      * IMPORTANT: Calls to this method must be within a synchronized block on this
293      * logger.
294      * 
295      * @param lastPart
296      *          the suffix (i.e. last part) of the child logger name. This
297      *          parameter may not include dots, i.e. the logger separator
298      *          character.
299      * @return
300      */

301     Logger createChildByLastNamePart(final String lastPart) {
302         int i_index = LoggerNameUtil.getFirstSeparatorIndexOf(lastPart);
303         if (i_index != -1) {
304             throw new IllegalArgumentException("Child name [" + lastPart + " passed as parameter, may not include [" + CoreConstants.DOT + "]");
305         }
306
307         if (childrenList == null) {
308             childrenList = new CopyOnWriteArrayList<Logger>();
309         }
310         Logger childLogger;
311         if (this.isRootLogger()) {
312             childLogger = new Logger(lastPart, thisthis.loggerContext);
313         } else {
314             childLogger = new Logger(name + CoreConstants.DOT + lastPart, thisthis.loggerContext);
315         }
316         childrenList.add(childLogger);
317         childLogger.effectiveLevelInt = this.effectiveLevelInt;
318         return childLogger;
319     }
320
321     private void localLevelReset() {
322         effectiveLevelInt = Level.DEBUG_INT;
323         if (isRootLogger()) {
324             level = Level.DEBUG;
325         } else {
326             level = null;
327         }
328     }
329
330     void recursiveReset() {
331         detachAndStopAllAppenders();
332         localLevelReset();
333         additive = true;
334         if (childrenList == null) {
335             return;
336         }
337         for (Logger childLogger : childrenList) {
338             childLogger.recursiveReset();
339         }
340     }
341
342     /**
343      * The default size of child list arrays. The JDK 1.5 default is 10. We use a
344      * smaller value to save a little space.
345      */

346
347     Logger createChildByName(final String childName) {
348         int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
349         if (i_index != -1) {
350             throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
351                             + " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
352         }
353
354         if (childrenList == null) {
355             childrenList = new CopyOnWriteArrayList<Logger>();
356         }
357         Logger childLogger;
358         childLogger = new Logger(childName, thisthis.loggerContext);
359         childrenList.add(childLogger);
360         childLogger.effectiveLevelInt = this.effectiveLevelInt;
361         return childLogger;
362     }
363
364     /**
365      * The next methods are not merged into one because of the time we gain by not
366      * creating a new Object[] with the params. This reduces the cost of not
367      * logging by about 20 nanoseconds.
368      */

369
370     private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
371                     final Throwable t) {
372
373         final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
374
375         if (decision == FilterReply.NEUTRAL) {
376             if (effectiveLevelInt > level.levelInt) {
377                 return;
378             }
379         } else if (decision == FilterReply.DENY) {
380             return;
381         }
382
383         buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
384     }
385
386     private void filterAndLog_1(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param, final Throwable t) {
387
388         final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(marker, this, level, msg, param, t);
389
390         if (decision == FilterReply.NEUTRAL) {
391             if (effectiveLevelInt > level.levelInt) {
392                 return;
393             }
394         } else if (decision == FilterReply.DENY) {
395             return;
396         }
397
398         buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param }, t);
399     }
400
401     private void filterAndLog_2(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param1, final Object param2,
402                     final Throwable t) {
403
404         final FilterReply decision = loggerContext.getTurboFilterChainDecision_2(marker, this, level, msg, param1, param2, t);
405
406         if (decision == FilterReply.NEUTRAL) {
407             if (effectiveLevelInt > level.levelInt) {
408                 return;
409             }
410         } else if (decision == FilterReply.DENY) {
411             return;
412         }
413
414         buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param1, param2 }, t);
415     }
416
417     private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
418                     final Throwable t) {
419         LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
420         le.setMarker(marker);
421         callAppenders(le);
422     }
423
424     public void trace(String msg) {
425         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, nullnull);
426     }
427
428     public void trace(String format, Object arg) {
429         filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null);
430     }
431
432     public void trace(String format, Object arg1, Object arg2) {
433         filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null);
434     }
435
436     public void trace(String format, Object... argArray) {
437         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null);
438     }
439
440     public void trace(String msg, Throwable t) {
441         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t);
442     }
443
444     public void trace(Marker marker, String msg) {
445         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, nullnull);
446     }
447
448     public void trace(Marker marker, String format, Object arg) {
449         filterAndLog_1(FQCN, marker, Level.TRACE, format, arg, null);
450     }
451
452     public void trace(Marker marker, String format, Object arg1, Object arg2) {
453         filterAndLog_2(FQCN, marker, Level.TRACE, format, arg1, arg2, null);
454     }
455
456     public void trace(Marker marker, String format, Object... argArray) {
457         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, format, argArray, null);
458     }
459
460     public void trace(Marker marker, String msg, Throwable t) {
461         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, t);
462     }
463
464     public boolean isDebugEnabled() {
465         return isDebugEnabled(null);
466     }
467
468     public boolean isDebugEnabled(Marker marker) {
469         final FilterReply decision = callTurboFilters(marker, Level.DEBUG);
470         if (decision == FilterReply.NEUTRAL) {
471             return effectiveLevelInt <= Level.DEBUG_INT;
472         } else if (decision == FilterReply.DENY) {
473             return false;
474         } else if (decision == FilterReply.ACCEPT) {
475             return true;
476         } else {
477             throw new IllegalStateException("Unknown FilterReply value: " + decision);
478         }
479     }
480
481     public void debug(String msg) {
482         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, nullnull);
483     }
484
485     public void debug(String format, Object arg) {
486         filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null);
487     }
488
489     public void debug(String format, Object arg1, Object arg2) {
490         filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null);
491     }
492
493     public void debug(String format, Object... argArray) {
494         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null);
495     }
496
497     public void debug(String msg, Throwable t) {
498         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t);
499     }
500
501     public void debug(Marker marker, String msg) {
502         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, nullnull);
503     }
504
505     public void debug(Marker marker, String format, Object arg) {
506         filterAndLog_1(FQCN, marker, Level.DEBUG, format, arg, null);
507     }
508
509     public void debug(Marker marker, String format, Object arg1, Object arg2) {
510         filterAndLog_2(FQCN, marker, Level.DEBUG, format, arg1, arg2, null);
511     }
512
513     public void debug(Marker marker, String format, Object... argArray) {
514         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, format, argArray, null);
515     }
516
517     public void debug(Marker marker, String msg, Throwable t) {
518         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, t);
519     }
520
521     public void error(String msg) {
522         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, nullnull);
523     }
524
525     public void error(String format, Object arg) {
526         filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null);
527     }
528
529     public void error(String format, Object arg1, Object arg2) {
530         filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null);
531     }
532
533     public void error(String format, Object... argArray) {
534         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null);
535     }
536
537     public void error(String msg, Throwable t) {
538         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t);
539     }
540
541     public void error(Marker marker, String msg) {
542         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, nullnull);
543     }
544
545     public void error(Marker marker, String format, Object arg) {
546         filterAndLog_1(FQCN, marker, Level.ERROR, format, arg, null);
547     }
548
549     public void error(Marker marker, String format, Object arg1, Object arg2) {
550         filterAndLog_2(FQCN, marker, Level.ERROR, format, arg1, arg2, null);
551     }
552
553     public void error(Marker marker, String format, Object... argArray) {
554         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, format, argArray, null);
555     }
556
557     public void error(Marker marker, String msg, Throwable t) {
558         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, t);
559     }
560
561     public boolean isInfoEnabled() {
562         return isInfoEnabled(null);
563     }
564
565     public boolean isInfoEnabled(Marker marker) {
566         FilterReply decision = callTurboFilters(marker, Level.INFO);
567         if (decision == FilterReply.NEUTRAL) {
568             return effectiveLevelInt <= Level.INFO_INT;
569         } else if (decision == FilterReply.DENY) {
570             return false;
571         } else if (decision == FilterReply.ACCEPT) {
572             return true;
573         } else {
574             throw new IllegalStateException("Unknown FilterReply value: " + decision);
575         }
576     }
577
578     public void info(String msg) {
579         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, nullnull);
580     }
581
582     public void info(String format, Object arg) {
583         filterAndLog_1(FQCN, null, Level.INFO, format, arg, null);
584     }
585
586     public void info(String format, Object arg1, Object arg2) {
587         filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null);
588     }
589
590     public void info(String format, Object... argArray) {
591         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null);
592     }
593
594     public void info(String msg, Throwable t) {
595         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t);
596     }
597
598     public void info(Marker marker, String msg) {
599         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, nullnull);
600     }
601
602     public void info(Marker marker, String format, Object arg) {
603         filterAndLog_1(FQCN, marker, Level.INFO, format, arg, null);
604     }
605
606     public void info(Marker marker, String format, Object arg1, Object arg2) {
607         filterAndLog_2(FQCN, marker, Level.INFO, format, arg1, arg2, null);
608     }
609
610     public void info(Marker marker, String format, Object... argArray) {
611         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, format, argArray, null);
612     }
613
614     public void info(Marker marker, String msg, Throwable t) {
615         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, t);
616     }
617
618     public boolean isTraceEnabled() {
619         return isTraceEnabled(null);
620     }
621
622     public boolean isTraceEnabled(Marker marker) {
623         final FilterReply decision = callTurboFilters(marker, Level.TRACE);
624         if (decision == FilterReply.NEUTRAL) {
625             return effectiveLevelInt <= Level.TRACE_INT;
626         } else if (decision == FilterReply.DENY) {
627             return false;
628         } else if (decision == FilterReply.ACCEPT) {
629             return true;
630         } else {
631             throw new IllegalStateException("Unknown FilterReply value: " + decision);
632         }
633     }
634
635     public boolean isErrorEnabled() {
636         return isErrorEnabled(null);
637     }
638
639     public boolean isErrorEnabled(Marker marker) {
640         FilterReply decision = callTurboFilters(marker, Level.ERROR);
641         if (decision == FilterReply.NEUTRAL) {
642             return effectiveLevelInt <= Level.ERROR_INT;
643         } else if (decision == FilterReply.DENY) {
644             return false;
645         } else if (decision == FilterReply.ACCEPT) {
646             return true;
647         } else {
648             throw new IllegalStateException("Unknown FilterReply value: " + decision);
649         }
650     }
651
652     public boolean isWarnEnabled() {
653         return isWarnEnabled(null);
654     }
655
656     public boolean isWarnEnabled(Marker marker) {
657         FilterReply decision = callTurboFilters(marker, Level.WARN);
658         if (decision == FilterReply.NEUTRAL) {
659             return effectiveLevelInt <= Level.WARN_INT;
660         } else if (decision == FilterReply.DENY) {
661             return false;
662         } else if (decision == FilterReply.ACCEPT) {
663             return true;
664         } else {
665             throw new IllegalStateException("Unknown FilterReply value: " + decision);
666         }
667
668     }
669
670     public boolean isEnabledFor(Marker marker, Level level) {
671         FilterReply decision = callTurboFilters(marker, level);
672         if (decision == FilterReply.NEUTRAL) {
673             return effectiveLevelInt <= level.levelInt;
674         } else if (decision == FilterReply.DENY) {
675             return false;
676         } else if (decision == FilterReply.ACCEPT) {
677             return true;
678         } else {
679             throw new IllegalStateException("Unknown FilterReply value: " + decision);
680         }
681     }
682
683     public boolean isEnabledFor(Level level) {
684         return isEnabledFor(null, level);
685     }
686
687     public void warn(String msg) {
688         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, nullnull);
689     }
690
691     public void warn(String msg, Throwable t) {
692         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t);
693     }
694
695     public void warn(String format, Object arg) {
696         filterAndLog_1(FQCN, null, Level.WARN, format, arg, null);
697     }
698
699     public void warn(String format, Object arg1, Object arg2) {
700         filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null);
701     }
702
703     public void warn(String format, Object... argArray) {
704         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null);
705     }
706
707     public void warn(Marker marker, String msg) {
708         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, nullnull);
709     }
710
711     public void warn(Marker marker, String format, Object arg) {
712         filterAndLog_1(FQCN, marker, Level.WARN, format, arg, null);
713     }
714
715     public void warn(Marker marker, String format, Object... argArray) {
716         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, format, argArray, null);
717     }
718
719     public void warn(Marker marker, String format, Object arg1, Object arg2) {
720         filterAndLog_2(FQCN, marker, Level.WARN, format, arg1, arg2, null);
721     }
722
723     public void warn(Marker marker, String msg, Throwable t) {
724         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, t);
725     }
726
727     public boolean isAdditive() {
728         return additive;
729     }
730
731     public void setAdditive(boolean additive) {
732         this.additive = additive;
733     }
734
735     public String toString() {
736         return "Logger[" + name + "]";
737     }
738
739     /**
740      * Method that calls the attached TurboFilter objects based on the logger and
741      * the level.
742      * 
743      * It is used by isYYYEnabled() methods.
744      * 
745      * It returns the typical FilterReply values: ACCEPT, NEUTRAL or DENY.
746      * 
747      * @param level
748      * @return the reply given by the TurboFilters
749      */

750     private FilterReply callTurboFilters(Marker marker, Level level) {
751         return loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, nullnullnull);
752     }
753
754     /**
755      * Return the context for this logger.
756      * 
757      * @return the context
758      */

759     public LoggerContext getLoggerContext() {
760         return loggerContext;
761     }
762
763     public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable t) {
764         Level level = Level.fromLocationAwareLoggerInteger(levelInt);
765         filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
766     }
767
768     /**
769      * Support SLF4J interception during initialization as introduced in SLF4J version 1.7.15
770      * @since 1.1.4 
771      * @param slf4jEvent
772      */

773     public void log(org.slf4j.event.LoggingEvent slf4jEvent) {
774         Level level = Level.fromLocationAwareLoggerInteger(slf4jEvent.getLevel().toInt());
775         filterAndLog_0_Or3Plus(FQCN, slf4jEvent.getMarker(), level, slf4jEvent.getMessage(), slf4jEvent.getArgumentArray(), slf4jEvent.getThrowable());
776     }
777
778     /**
779      * After serialization, the logger instance does not know its LoggerContext.
780      * The best we can do here, is to return a logger with the same name
781      * returned by org.slf4j.LoggerFactory.
782      * 
783      * @return Logger instance with the same name
784      * @throws ObjectStreamException
785      */

786     protected Object readResolve() throws ObjectStreamException {
787         return LoggerFactory.getLogger(getName());
788     }
789 }
790