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.DefaultLoggingEventBuilder;
026import org.slf4j.spi.LocationAwareLogger;
027import org.slf4j.spi.LoggingEventAware;
028import org.slf4j.spi.LoggingEventBuilder;
029
030import ch.qos.logback.classic.spi.ILoggingEvent;
031import ch.qos.logback.classic.spi.LoggingEvent;
032import ch.qos.logback.classic.util.LoggerNameUtil;
033import ch.qos.logback.core.Appender;
034import ch.qos.logback.core.CoreConstants;
035import ch.qos.logback.core.spi.AppenderAttachable;
036import ch.qos.logback.core.spi.AppenderAttachableImpl;
037import ch.qos.logback.core.spi.FilterReply;
038
039public final class Logger
040        implements org.slf4j.Logger, LocationAwareLogger, LoggingEventAware, AppenderAttachable<ILoggingEvent>, Serializable {
041
042    private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
043
044    /**
045     * The fully qualified name of this class. Used in gathering caller information.
046     */
047    public static final String FQCN = ch.qos.logback.classic.Logger.class.getName();
048
049    /**
050     * The name of this logger
051     */
052    private String name;
053
054    // The assigned levelInt of this logger. Can be null.
055    transient private Level level;
056
057    // The effective levelInt is the assigned levelInt and if null, a levelInt is
058    // inherited form a parent.
059    transient private int effectiveLevelInt;
060
061    /**
062     * The parent of this category. All categories have at least one ancestor which
063     * is the root category.
064     */
065    transient private Logger parent;
066
067    /**
068     * The children of this logger. A logger may have zero or more children.
069     */
070    transient private List<Logger> childrenList;
071
072    /**
073     * It is assumed that once the 'aai' variable is set to a non-null value, it
074     * will never be reset to null. it is further assumed that only place where the
075     * 'aai'ariable is set is within the addAppender method. This method is
076     * synchronized on 'this' (Logger) protecting against simultaneous
077     * re-configuration of this logger (a very unlikely scenario).
078     * 
079     * <p>
080     * It is further assumed that the AppenderAttachableImpl is responsible for its
081     * internal synchronization and thread safety. Thus, we can get away with *not*
082     * synchronizing on the 'aai' (check null/ read) because
083     * <p>
084     * 1) the 'aai' variable is immutable once set to non-null
085     * <p>
086     * 2) 'aai' is getAndSet only within addAppender which is synchronized
087     * <p>
088     * 3) all the other methods check whether 'aai' is null
089     * <p>
090     * 4) AppenderAttachableImpl is thread safe
091     */
092    transient private AppenderAttachableImpl<ILoggingEvent> aai;
093    /**
094     * Additivity is set to true by default, that is children inherit the appenders
095     * of their ancestors by default. If this variable is set to <code>false</code>
096     * then the appenders located in the ancestors of this logger will not be used.
097     * However, the children of this logger will inherit its appenders, unless the
098     * children have their additivity flag set to <code>false</code> too. See the
099     * 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}