View Javadoc
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, this, this.loggerContext);
313         } else {
314             childLogger = new Logger(name + CoreConstants.DOT + lastPart, this, this.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, this, this.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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null);
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, null, null, null);
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 }