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.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'ariable 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     private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level,
373             final String msg, final Object[] params, final Throwable t) {
374 
375         final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg,
376                 params, t);
377 
378         if (decision == FilterReply.NEUTRAL) {
379             if (effectiveLevelInt > level.levelInt) {
380                 return;
381             }
382         } else if (decision == FilterReply.DENY) {
383             return;
384         }
385 
386         buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
387     }
388 
389     private void filterAndLog_1(final String localFQCN, final Marker marker, final Level level, final String msg,
390             final Object param, final Throwable t) {
391 
392         final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(marker, this, level, msg, param, t);
393 
394         if (decision == FilterReply.NEUTRAL) {
395             if (effectiveLevelInt > level.levelInt) {
396                 return;
397             }
398         } else if (decision == FilterReply.DENY) {
399             return;
400         }
401 
402         buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param }, t);
403     }
404 
405     private void filterAndLog_2(final String localFQCN, final Marker marker, final Level level, final String msg,
406             final Object param1, final Object param2, final Throwable t) {
407 
408         final FilterReply decision = loggerContext.getTurboFilterChainDecision_2(marker, this, level, msg, param1,
409                 param2, t);
410 
411         if (decision == FilterReply.NEUTRAL) {
412             if (effectiveLevelInt > level.levelInt) {
413                 return;
414             }
415         } else if (decision == FilterReply.DENY) {
416             return;
417         }
418 
419         buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param1, param2 }, t);
420     }
421 
422     private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level,
423             final String msg, final Object[] params, final Throwable t) {
424         LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
425         le.addMarker(marker);
426         callAppenders(le);
427     }
428 
429     public void trace(String msg) {
430         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, null);
431     }
432 
433     public void trace(String format, Object arg) {
434         filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null);
435     }
436 
437     public void trace(String format, Object arg1, Object arg2) {
438         filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null);
439     }
440 
441     public void trace(String format, Object... argArray) {
442         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null);
443     }
444 
445     public void trace(String msg, Throwable t) {
446         filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t);
447     }
448 
449     public void trace(Marker marker, String msg) {
450         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, null);
451     }
452 
453     public void trace(Marker marker, String format, Object arg) {
454         filterAndLog_1(FQCN, marker, Level.TRACE, format, arg, null);
455     }
456 
457     public void trace(Marker marker, String format, Object arg1, Object arg2) {
458         filterAndLog_2(FQCN, marker, Level.TRACE, format, arg1, arg2, null);
459     }
460 
461     public void trace(Marker marker, String format, Object... argArray) {
462         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, format, argArray, null);
463     }
464 
465     public void trace(Marker marker, String msg, Throwable t) {
466         filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, t);
467     }
468 
469     public boolean isDebugEnabled() {
470         return isDebugEnabled(null);
471     }
472 
473     public boolean isDebugEnabled(Marker marker) {
474         final FilterReply decision = callTurboFilters(marker, Level.DEBUG);
475         if (decision == FilterReply.NEUTRAL) {
476             return effectiveLevelInt <= Level.DEBUG_INT;
477         } else if (decision == FilterReply.DENY) {
478             return false;
479         } else if (decision == FilterReply.ACCEPT) {
480             return true;
481         } else {
482             throw new IllegalStateException("Unknown FilterReply value: " + decision);
483         }
484     }
485 
486     public void debug(String msg) {
487         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, null);
488     }
489 
490     public void debug(String format, Object arg) {
491         filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null);
492     }
493 
494     public void debug(String format, Object arg1, Object arg2) {
495         filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null);
496     }
497 
498     public void debug(String format, Object... argArray) {
499         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null);
500     }
501 
502     public void debug(String msg, Throwable t) {
503         filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t);
504     }
505 
506     public void debug(Marker marker, String msg) {
507         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, null);
508     }
509 
510     public void debug(Marker marker, String format, Object arg) {
511         filterAndLog_1(FQCN, marker, Level.DEBUG, format, arg, null);
512     }
513 
514     public void debug(Marker marker, String format, Object arg1, Object arg2) {
515         filterAndLog_2(FQCN, marker, Level.DEBUG, format, arg1, arg2, null);
516     }
517 
518     public void debug(Marker marker, String format, Object... argArray) {
519         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, format, argArray, null);
520     }
521 
522     public void debug(Marker marker, String msg, Throwable t) {
523         filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, t);
524     }
525 
526     public void error(String msg) {
527         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, null);
528     }
529 
530     public void error(String format, Object arg) {
531         filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null);
532     }
533 
534     public void error(String format, Object arg1, Object arg2) {
535         filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null);
536     }
537 
538     public void error(String format, Object... argArray) {
539         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null);
540     }
541 
542     public void error(String msg, Throwable t) {
543         filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t);
544     }
545 
546     public void error(Marker marker, String msg) {
547         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, null);
548     }
549 
550     public void error(Marker marker, String format, Object arg) {
551         filterAndLog_1(FQCN, marker, Level.ERROR, format, arg, null);
552     }
553 
554     public void error(Marker marker, String format, Object arg1, Object arg2) {
555         filterAndLog_2(FQCN, marker, Level.ERROR, format, arg1, arg2, null);
556     }
557 
558     public void error(Marker marker, String format, Object... argArray) {
559         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, format, argArray, null);
560     }
561 
562     public void error(Marker marker, String msg, Throwable t) {
563         filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, t);
564     }
565 
566     public boolean isInfoEnabled() {
567         return isInfoEnabled(null);
568     }
569 
570     public boolean isInfoEnabled(Marker marker) {
571         FilterReply decision = callTurboFilters(marker, Level.INFO);
572         if (decision == FilterReply.NEUTRAL) {
573             return effectiveLevelInt <= Level.INFO_INT;
574         } else if (decision == FilterReply.DENY) {
575             return false;
576         } else if (decision == FilterReply.ACCEPT) {
577             return true;
578         } else {
579             throw new IllegalStateException("Unknown FilterReply value: " + decision);
580         }
581     }
582 
583     public void info(String msg) {
584         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
585     }
586 
587     public void info(String format, Object arg) {
588         filterAndLog_1(FQCN, null, Level.INFO, format, arg, null);
589     }
590 
591     public void info(String format, Object arg1, Object arg2) {
592         filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null);
593     }
594 
595     public void info(String format, Object... argArray) {
596         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null);
597     }
598 
599     public void info(String msg, Throwable t) {
600         filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t);
601     }
602 
603     public void info(Marker marker, String msg) {
604         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, null);
605     }
606 
607     public void info(Marker marker, String format, Object arg) {
608         filterAndLog_1(FQCN, marker, Level.INFO, format, arg, null);
609     }
610 
611     public void info(Marker marker, String format, Object arg1, Object arg2) {
612         filterAndLog_2(FQCN, marker, Level.INFO, format, arg1, arg2, null);
613     }
614 
615     public void info(Marker marker, String format, Object... argArray) {
616         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, format, argArray, null);
617     }
618 
619     public void info(Marker marker, String msg, Throwable t) {
620         filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, t);
621     }
622 
623     public boolean isTraceEnabled() {
624         return isTraceEnabled(null);
625     }
626 
627     public boolean isTraceEnabled(Marker marker) {
628         final FilterReply decision = callTurboFilters(marker, Level.TRACE);
629         if (decision == FilterReply.NEUTRAL) {
630             return effectiveLevelInt <= Level.TRACE_INT;
631         } else if (decision == FilterReply.DENY) {
632             return false;
633         } else if (decision == FilterReply.ACCEPT) {
634             return true;
635         } else {
636             throw new IllegalStateException("Unknown FilterReply value: " + decision);
637         }
638     }
639 
640     public boolean isErrorEnabled() {
641         return isErrorEnabled(null);
642     }
643 
644     public boolean isErrorEnabled(Marker marker) {
645         FilterReply decision = callTurboFilters(marker, Level.ERROR);
646         if (decision == FilterReply.NEUTRAL) {
647             return effectiveLevelInt <= Level.ERROR_INT;
648         } else if (decision == FilterReply.DENY) {
649             return false;
650         } else if (decision == FilterReply.ACCEPT) {
651             return true;
652         } else {
653             throw new IllegalStateException("Unknown FilterReply value: " + decision);
654         }
655     }
656 
657     public boolean isWarnEnabled() {
658         return isWarnEnabled(null);
659     }
660 
661     public boolean isWarnEnabled(Marker marker) {
662         FilterReply decision = callTurboFilters(marker, Level.WARN);
663         if (decision == FilterReply.NEUTRAL) {
664             return effectiveLevelInt <= Level.WARN_INT;
665         } else if (decision == FilterReply.DENY) {
666             return false;
667         } else if (decision == FilterReply.ACCEPT) {
668             return true;
669         } else {
670             throw new IllegalStateException("Unknown FilterReply value: " + decision);
671         }
672 
673     }
674 
675     public boolean isEnabledFor(Marker marker, Level level) {
676         FilterReply decision = callTurboFilters(marker, level);
677         if (decision == FilterReply.NEUTRAL) {
678             return effectiveLevelInt <= level.levelInt;
679         } else if (decision == FilterReply.DENY) {
680             return false;
681         } else if (decision == FilterReply.ACCEPT) {
682             return true;
683         } else {
684             throw new IllegalStateException("Unknown FilterReply value: " + decision);
685         }
686     }
687 
688     public boolean isEnabledFor(Level level) {
689         return isEnabledFor(null, level);
690     }
691 
692     public void warn(String msg) {
693         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, null);
694     }
695 
696     public void warn(String msg, Throwable t) {
697         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t);
698     }
699 
700     public void warn(String format, Object arg) {
701         filterAndLog_1(FQCN, null, Level.WARN, format, arg, null);
702     }
703 
704     public void warn(String format, Object arg1, Object arg2) {
705         filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null);
706     }
707 
708     public void warn(String format, Object... argArray) {
709         filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null);
710     }
711 
712     public void warn(Marker marker, String msg) {
713         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, null);
714     }
715 
716     public void warn(Marker marker, String format, Object arg) {
717         filterAndLog_1(FQCN, marker, Level.WARN, format, arg, null);
718     }
719 
720     public void warn(Marker marker, String format, Object... argArray) {
721         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, format, argArray, null);
722     }
723 
724     public void warn(Marker marker, String format, Object arg1, Object arg2) {
725         filterAndLog_2(FQCN, marker, Level.WARN, format, arg1, arg2, null);
726     }
727 
728     public void warn(Marker marker, String msg, Throwable t) {
729         filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, t);
730     }
731 
732     public boolean isAdditive() {
733         return additive;
734     }
735 
736     public void setAdditive(boolean additive) {
737         this.additive = additive;
738     }
739 
740     public String toString() {
741         return "Logger[" + name + "]";
742     }
743 
744     /**
745      * Method that calls the attached TurboFilter objects based on the logger and
746      * the level.
747      * 
748      * It is used by isYYYEnabled() methods.
749      * 
750      * It returns the typical FilterReply values: ACCEPT, NEUTRAL or DENY.
751      * 
752      * @param level
753      * @return the reply given by the TurboFilters
754      */
755     private FilterReply callTurboFilters(Marker marker, Level level) {
756         return loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, null, null, null);
757     }
758 
759     /**
760      * Return the context for this logger.
761      * 
762      * @return the context
763      */
764     public LoggerContext getLoggerContext() {
765         return loggerContext;
766     }
767 
768     /**
769      * Creates a {@link LoggingEventBuilder} of type {@link DefaultLoggingEventBuilder}.
770      * 
771      * @since 1.3
772      */
773     @Override
774     public LoggingEventBuilder makeLoggingEventBuilder(org.slf4j.event.Level level) {
775         return new DefaultLoggingEventBuilder(this, level);
776     }
777 
778     public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable t) {
779         Level level = Level.fromLocationAwareLoggerInteger(levelInt);
780         filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
781     }
782 
783     /**
784      * Support SLF4J interception during initialization as introduced in SLF4J
785      * version 1.7.15
786      * 
787      * @since 1.1.4
788      * @param slf4jEvent
789      */
790     public void log(org.slf4j.event.LoggingEvent slf4jEvent) {
791         org.slf4j.event.Level slf4jLevel = slf4jEvent.getLevel();
792         Level logbackLevel = Level.convertAnSLF4JLevel(slf4jLevel);
793 
794         // By default, assume this class was the caller. This happens during
795         // initialization.
796         // However, it is possible that the caller is some other library, e.g.
797         // slf4j-jdk-platform-logging
798 
799         String callerBoundary = slf4jEvent.getCallerBoundary();
800         if (callerBoundary == null) {
801             callerBoundary = FQCN;
802         }
803 
804         LoggingEvent lle = new LoggingEvent(callerBoundary, this, logbackLevel, slf4jEvent.getMessage(),
805                 slf4jEvent.getThrowable(), slf4jEvent.getArgumentArray());
806         List<Marker> markers = slf4jEvent.getMarkers();
807 
808         if (markers != null) {
809             markers.forEach(m -> lle.addMarker(m));
810         }
811 
812         lle.setKeyValuePairs(slf4jEvent.getKeyValuePairs());
813 
814         // Note that at this point, any calls made with a logger disabled
815         // for a given level, will be already filtered out/in. TurboFilters cannot
816         // act at this point in the process.
817         this.callAppenders(lle);
818     }
819 
820     /**
821      * After serialization, the logger instance does not know its LoggerContext. The
822      * best we can do here, is to return a logger with the same name returned by
823      * org.slf4j.LoggerFactory.
824      * 
825      * @return Logger instance with the same name
826      * @throws ObjectStreamException
827      */
828     protected Object readResolve() throws ObjectStreamException {
829         return LoggerFactory.getLogger(getName());
830     }
831 }