001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic;
015
016import java.io.ObjectStreamException;
017import java.io.Serializable;
018import java.util.Collections;
019import java.util.Iterator;
020import java.util.List;
021import java.util.concurrent.CopyOnWriteArrayList;
022
023import org.slf4j.LoggerFactory;
024import org.slf4j.Marker;
025import org.slf4j.spi.LocationAwareLogger;
026
027import ch.qos.logback.classic.spi.ILoggingEvent;
028import ch.qos.logback.classic.spi.LoggingEvent;
029import ch.qos.logback.classic.util.LoggerNameUtil;
030import ch.qos.logback.core.Appender;
031import ch.qos.logback.core.CoreConstants;
032import ch.qos.logback.core.spi.AppenderAttachable;
033import ch.qos.logback.core.spi.AppenderAttachableImpl;
034import ch.qos.logback.core.spi.FilterReply;
035
036public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
037
038    private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
039
040    /**
041     * The fully qualified name of this class. Used in gathering caller
042     * information.
043     */
044    public static final String FQCN = ch.qos.logback.classic.Logger.class.getName();
045
046    /**
047     * The name of this logger
048     */
049    private String name;
050
051    // The assigned levelInt of this logger. Can be null.
052    transient private Level level;
053
054    // The effective levelInt is the assigned levelInt and if null, a levelInt is
055    // inherited form a parent.
056    transient private int effectiveLevelInt;
057
058    /**
059     * The parent of this category. All categories have at least one ancestor
060     * which is the root category.
061     */
062    transient private Logger parent;
063
064    /**
065     * The children of this logger. A logger may have zero or more children.
066     */
067    transient private List<Logger> childrenList;
068
069    /**
070     * It is assumed that once the 'aai' variable is set to a non-null value, it
071     * will never be reset to null. it is further assumed that only place where
072     * the 'aai'ariable is set is within the addAppender method. This method is
073     * synchronized on 'this' (Logger) protecting against simultaneous
074     * re-configuration of this logger (a very unlikely scenario).
075     * 
076     * <p>
077     * It is further assumed that the AppenderAttachableImpl is responsible for
078     * its internal synchronization and thread safety. Thus, we can get away with
079     * *not* synchronizing on the 'aai' (check null/ read) because
080     * <p>
081     * 1) the 'aai' variable is immutable once set to non-null
082     * <p>
083     * 2) 'aai' is getAndSet only within addAppender which is synchronized
084     * <p>
085     * 3) all the other methods check whether 'aai' is null
086     * <p>
087     * 4) AppenderAttachableImpl is thread safe
088     */
089    transient private AppenderAttachableImpl<ILoggingEvent> aai;
090    /**
091     * Additivity is set to true by default, that is children inherit the
092     * appenders of their ancestors by default. If this variable is set to
093     * <code>false</code> then the appenders located in the ancestors of this
094     * logger will not be used. However, the children of this logger will inherit
095     * its appenders, unless the children have their additivity flag set to
096     * <code>false</code> too. See the user manual for more details.
097     */
098    transient private boolean additive = true;
099
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}