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