• logger(四)、springBoot的日志源码查看(LogBack + slf4j)——记录日志


    上篇博客介绍了LoggerContext怎么生成Logger,Logger是logback的核心类,也是所有日志框架的核心类。这篇博客详细介绍一下Logger的各字段和方法,重点介绍Logger类是怎样记录日志的

     Logger类实现了slf4j框架定义的Logger接口,然后这个类和LoggerContext是互相引用的(因为Logger需要依赖LoggerContext的TurboFilter等组件)。并且Logger实现了AppenderAttachable接口,它实现该接口的方式,是持有AppenderAttachableImpl类,然后委托该类来实现AppenderAttachable接口定义的方法,这里用到了代理模式,是一个比较精巧的设计

    看到了Logger类的全景图,接下来我们逐一介绍Logger类中的各个字段,最后重点介绍Logger类是怎样记录日志的

    首先看看Logger的字段

    public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
    
        private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
    
        /**
         * 此类的完全限定名称。用于收集呼叫者信息。
         */
        public static final String FQCN = ch.qos.logback.classic.Logger.class.getName();
    
        /**
         * Logger的名称
         */
        private String name;
    
        // 此记录器的指定 levelInt。 可以为空。
        transient private Level level;
    
        // 有效的 levelInt 是分配的 levelInt,如果为 null,则从父级继承 levelInt。
        transient private int effectiveLevelInt;
    
        /**
         * 此类别的父级。 所有类别至少有一个祖先,即根类别。
         */
        transient private Logger parent;
    
        /**
         * 这个记录器的孩子。 一个记录器可能有零个或多个子节点。
         */
        transient private List<Logger> childrenList;
    
        /**
         * It is assumed that once the 'aai' variable is set to a non-null value, it
         * will never be reset to null. it is further assumed that only place where
         * the 'aai'ariable is set is within the addAppender method. This method is
         * synchronized on 'this' (Logger) protecting against simultaneous
         * re-configuration of this logger (a very unlikely scenario).
         * 
         * <p>
         * It is further assumed that the AppenderAttachableImpl is responsible for
         * its internal synchronization and thread safety. Thus, we can get away with
         * *not* synchronizing on the 'aai' (check null/ read) because
         * <p>
         * 1) the 'aai' variable is immutable once set to non-null
         * <p>
         * 2) 'aai' is getAndSet only within addAppender which is synchronized
         * <p>
         * 3) all the other methods check whether 'aai' is null
         * <p>
         * 4) AppenderAttachableImpl is thread safe
         */
        transient private AppenderAttachableImpl<ILoggingEvent> aai;
        /**
         * Additivity is set to true by default, that is children inherit the
         * appenders of their ancestors by default. If this variable is set to
         * <code>false</code> then the appenders located in the ancestors of this
         * logger will not be used. However, the children of this logger will inherit
         * its appenders, unless the children have their additivity flag set to
         * <code>false</code> too. See the user manual for more details.
         */
        transient private boolean additive = true;
    
        final transient LoggerContext loggerContext;
    
        Logger(String name, Logger parent, LoggerContext loggerContext) {
            this.name = name;
            this.parent = parent;
            this.loggerContext = loggerContext;
        }

    1、name是Logger的名称
    2、level是该Logger的分配级别,当配置文件中没有配置时,这个分配级别可以为null
    3、effectiveLevelInt是该Logger的生效级别,会从父Logger继承得到
    4、parent和childrenList是这个Logger的父Logger和子Logger,体现了logback的Logger层次结构
    5、aai上面已经说到了,Logger是委托这个类实现AppenderAttachable接口,也是委托这个类来调用Appender组件来实际记录日志,所以这个字段是最关键的
    6、additive是这个类的Appender叠加性,具体看我的另一篇博客。该字段也是在配置文件中配置的,默认为true

    介绍完了字段,可以看到Logger的设计还是相当清晰易懂的, 接下来逐一看看Logger中的方法,getter和setter方法就不废话了 

        private boolean isRootLogger() {
            // only the root logger has a null parent
            return parent == null;
        }

    这个方法用来判断一个Logger是否是根Logger

     
        Logger getChildByName(final String childName) {
            if (childrenList == null) {
                return null;
            } else {
                int len = this.childrenList.size();
                for (int i = 0; i < len; i++) {
                    final Logger childLogger_i = (Logger) childrenList.get(i);
                    final String childName_i = childLogger_i.getName();
    
                    if (childName.equals(childName_i)) {
                        return childLogger_i;
                    }
                }
                // no child found
                return null;
            }
        }

    这个方法用来得到子Logger,是在LoggerContext的getLogger()方法里调用的,在上一篇博客里已经介绍过了

     
        public synchronized void setLevel(Level newLevel) {
            if (level == newLevel) {
                // nothing to do;
                return;
            }
            if (newLevel == null && isRootLogger()) {
                throw new IllegalArgumentException("The level of the root logger cannot be set to null");
            }
    
            level = newLevel;
            if (newLevel == null) {
                effectiveLevelInt = parent.effectiveLevelInt;
                newLevel = parent.getEffectiveLevel();
            } else {
                effectiveLevelInt = newLevel.levelInt;
            }
    
            if (childrenList != null) {
                int len = childrenList.size();
                for (int i = 0; i < len; i++) {
                    Logger child = (Logger) childrenList.get(i);
                    // tell child to handle parent levelInt change
                    child.handleParentLevelChange(effectiveLevelInt);
                }
            }
            // inform listeners
            loggerContext.fireOnLevelChange(this, newLevel);
        }
    
        /**
         * This method is invoked by parent logger to let this logger know that the
         * prent's levelInt changed.
         * 
         * @param newParentLevelInt
         */
        private synchronized void handleParentLevelChange(int newParentLevelInt) {
            // changes in the parent levelInt affect children only if their levelInt is
            // null
            if (level == null) {
                effectiveLevelInt = newParentLevelInt;
    
                // propagate the parent levelInt change to this logger's children
                if (childrenList != null) {
                    int len = childrenList.size();
                    for (int i = 0; i < len; i++) {
                        Logger child = (Logger) childrenList.get(i);
                        child.handleParentLevelChange(newParentLevelInt);
                    }
                }
            }
        }

    这2个方法是用来改变Logger的生效级别,并且连带改变子Logger的生效级别

     
        /**
         * The default size of child list arrays. The JDK 1.5 default is 10. We use a
         * smaller value to save a little space.
         */
    
        Logger createChildByName(final String childName) {
            int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
            if (i_index != -1) {
                throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
                                + " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
            }
    
            if (childrenList == null) {
                childrenList = new CopyOnWriteArrayList<Logger>();
            }
            Logger childLogger;
            childLogger = new Logger(childName, this, this.loggerContext);
            childrenList.add(childLogger);
            childLogger.effectiveLevelInt = this.effectiveLevelInt;
            return childLogger;
        }

    这个方法是用来创建子Logger的,并且会设置Logger的父子关系,也是在LoggerContext的getLogger()方法里调用的

     
    接下来就重点介绍Logger组件怎么记录日志了,slf4j定义了Logger接口记录日志的方法是info()、warn()、debug()等,这些方法只是入口,logback是这样实现这些方法的
     
        public void info(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
        }

    当客户端代码调用Logger.info()时,实际上会进入filterAndLog_0_Or3Plus方法,Logger类中还有很多名字很相似的方法,比如filterAndLog_1、filterAndLog_2。据作者自己说,之所以定义这一系列的方法,是为了提高logback的性能

        /**
         * The next methods are not merged into one because of the time we gain by not
         * creating a new Object[] with the params. This reduces the cost of not
         * logging by about 20 nanoseconds.下一个方法不会合并为一个方法,因为我们通过不使用参数创建新的 Object[] 获得了时间。 这将不记录的成本降低了大约 20 纳秒。
         */
    
        private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
                        final Throwable t) {
    
            final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
    
            if (decision == FilterReply.NEUTRAL) {
                if (effectiveLevelInt > level.levelInt) {
                    return;
                }
            } else if (decision == FilterReply.DENY) {
                return;
            }
    
            buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
        }

    该方法首先要请求TurboFilter来判断是否允许记录这次日志信息。TurboFilter是快速筛选的组件,筛选发生在LoggingEvent创建之前,这种设计也是为了提高性能

    如果经过过滤,确定要记录这条日志信息,则进入buildLoggingEventAndAppend方法

        private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
                        final Throwable t) {
            LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
            le.setMarker(marker);
            callAppenders(le);
        }

    在这个方法里,首先创建了LoggingEvent对象,然后调用callAppenders()方法,要求该Logger关联的所有Appenders来记录日志

    LoggingEvent对象是承载了日志信息的类,最后输出的日志信息,就来源于这个事件对象

        /**
         * Invoke all the appenders of this logger.
         * 
         * @param event
         *          The event to log
         */
        public void callAppenders(ILoggingEvent event) {
            int writes = 0;
            for (Logger l = this; l != null; l = l.parent) {
                writes += l.appendLoopOnAppenders(event);
                if (!l.additive) {
                    break;
                }
            }
            // No appenders in hierarchy
            if (writes == 0) {
                loggerContext.noAppenderDefinedWarning(this);
            }
        }

    经过前面的Filter过滤、日志级别匹配、创建LoggerEvent对象,终于进入了记录日志的方法。该方法会调用此Logger关联的所有Appender,而且还会调用所有父Logger关联的Appender,直到遇到父Logger的additive属性设置为false为止,这也是为什么如果子Logger和父Logger都关联了同样的Appender,则日志信息会重复记录的原因

    继续看下来
     
        private int appendLoopOnAppenders(ILoggingEvent event) {
            if (aai != null) {
                return aai.appendLoopOnAppenders(event);
            } else {
                return 0;
            }
        }

    实际上调用的AppenderAttachableImpl的appendLoopOnAppenders()方法

        /**
         * Call the <code>doAppend</code> method on all attached appenders.
         */
        public int appendLoopOnAppenders(E e) {
            int size = 0;
            final Appender<E>[] appenderArray = appenderList.asTypedArray();
            final int len = appenderArray.length;
            for (int i = 0; i < len; i++) {
                appenderArray[i].doAppend(e);
                size++;
            }
            return size;
        }

    到这里,为了记录一条日志信息,长长的调用链终于告一段落了,通过调用Appender的doAppend(LoggingEvent e)方法,委托Appender来最终记录日志(其实Appender记录日志信息也是委托其他的类来完成的, 在后面的博客中再介绍)

    总结:

    Logger类中定义的字段和方法,是出于以下目的:
    1、持有LoggerContext,是为了使用TurboFilter来进行快速过滤
    2、定义parent和childList,用于实现父子Logger的树形结构
    3、定义createChildByName()、getChildByName()方法,是供LoggerContext创建Logger
    4、定义level、effectiveLevelInt,是为了判定日志级别是否足够
    5、最后,filterAndLog()、buildLoggingEventAndAppend()、callAppenders()、appendLoopOnAppenders()方法,是Logger类的核心方法,一步步地委托AppenderAttachableImpl类来实际记录日志 

     
      

    完整代码如下:

    public final class Logger implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable<ILoggingEvent>, Serializable {
    
        private static final long serialVersionUID = 5454405123156820674L; // 8745934908040027998L;
    
        /**
         * The fully qualified name of this class. Used in gathering caller
         * information.
         */
        public static final String FQCN = ch.qos.logback.classic.Logger.class.getName();
    
        /**
         * The name of this logger
         */
        private String name;
    
        // The assigned levelInt of this logger. Can be null.
        transient private Level level;
    
        // The effective levelInt is the assigned levelInt and if null, a levelInt is
        // inherited form a parent.
        transient private int effectiveLevelInt;
    
        /**
         * The parent of this category. All categories have at least one ancestor
         * which is the root category.
         */
        transient private Logger parent;
    
        /**
         * The children of this logger. A logger may have zero or more children.
         */
        transient private List<Logger> childrenList;
    
        /**
         * It is assumed that once the 'aai' variable is set to a non-null value, it
         * will never be reset to null. it is further assumed that only place where
         * the 'aai'ariable is set is within the addAppender method. This method is
         * synchronized on 'this' (Logger) protecting against simultaneous
         * re-configuration of this logger (a very unlikely scenario).
         * 
         * <p>
         * It is further assumed that the AppenderAttachableImpl is responsible for
         * its internal synchronization and thread safety. Thus, we can get away with
         * *not* synchronizing on the 'aai' (check null/ read) because
         * <p>
         * 1) the 'aai' variable is immutable once set to non-null
         * <p>
         * 2) 'aai' is getAndSet only within addAppender which is synchronized
         * <p>
         * 3) all the other methods check whether 'aai' is null
         * <p>
         * 4) AppenderAttachableImpl is thread safe
         */
        transient private AppenderAttachableImpl<ILoggingEvent> aai;
        /**
         * Additivity is set to true by default, that is children inherit the
         * appenders of their ancestors by default. If this variable is set to
         * <code>false</code> then the appenders located in the ancestors of this
         * logger will not be used. However, the children of this logger will inherit
         * its appenders, unless the children have their additivity flag set to
         * <code>false</code> too. See the user manual for more details.
         */
        transient private boolean additive = true;
    
        final transient LoggerContext loggerContext;
    
        Logger(String name, Logger parent, LoggerContext loggerContext) {
            this.name = name;
            this.parent = parent;
            this.loggerContext = loggerContext;
        }
    
        public Level getEffectiveLevel() {
            return Level.toLevel(effectiveLevelInt);
        }
    
        int getEffectiveLevelInt() {
            return effectiveLevelInt;
        }
    
        public Level getLevel() {
            return level;
        }
    
        public String getName() {
            return name;
        }
    
        private boolean isRootLogger() {
            // only the root logger has a null parent
            return parent == null;
        }
    
        Logger getChildByName(final String childName) {
            if (childrenList == null) {
                return null;
            } else {
                int len = this.childrenList.size();
                for (int i = 0; i < len; i++) {
                    final Logger childLogger_i = (Logger) childrenList.get(i);
                    final String childName_i = childLogger_i.getName();
    
                    if (childName.equals(childName_i)) {
                        return childLogger_i;
                    }
                }
                // no child found
                return null;
            }
        }
    
        public synchronized void setLevel(Level newLevel) {
            if (level == newLevel) {
                // nothing to do;
                return;
            }
            if (newLevel == null && isRootLogger()) {
                throw new IllegalArgumentException("The level of the root logger cannot be set to null");
            }
    
            level = newLevel;
            if (newLevel == null) {
                effectiveLevelInt = parent.effectiveLevelInt;
                newLevel = parent.getEffectiveLevel();
            } else {
                effectiveLevelInt = newLevel.levelInt;
            }
    
            if (childrenList != null) {
                int len = childrenList.size();
                for (int i = 0; i < len; i++) {
                    Logger child = (Logger) childrenList.get(i);
                    // tell child to handle parent levelInt change
                    child.handleParentLevelChange(effectiveLevelInt);
                }
            }
            // inform listeners
            loggerContext.fireOnLevelChange(this, newLevel);
        }
    
        /**
         * This method is invoked by parent logger to let this logger know that the
         * prent's levelInt changed.
         * 
         * @param newParentLevelInt
         */
        private synchronized void handleParentLevelChange(int newParentLevelInt) {
            // changes in the parent levelInt affect children only if their levelInt is
            // null
            if (level == null) {
                effectiveLevelInt = newParentLevelInt;
    
                // propagate the parent levelInt change to this logger's children
                if (childrenList != null) {
                    int len = childrenList.size();
                    for (int i = 0; i < len; i++) {
                        Logger child = (Logger) childrenList.get(i);
                        child.handleParentLevelChange(newParentLevelInt);
                    }
                }
            }
        }
    
        /**
         * Remove all previously added appenders from this logger instance.
         * <p/>
         * This is useful when re-reading configuration information.
         */
        public void detachAndStopAllAppenders() {
            if (aai != null) {
                aai.detachAndStopAllAppenders();
            }
        }
    
        public boolean detachAppender(String name) {
            if (aai == null) {
                return false;
            }
            return aai.detachAppender(name);
        }
    
        // this method MUST be synchronized. See comments on 'aai' field for further
        // details.
        public synchronized void addAppender(Appender<ILoggingEvent> newAppender) {
            if (aai == null) {
                aai = new AppenderAttachableImpl<ILoggingEvent>();
            }
            aai.addAppender(newAppender);
        }
    
        public boolean isAttached(Appender<ILoggingEvent> appender) {
            if (aai == null) {
                return false;
            }
            return aai.isAttached(appender);
        }
    
        @SuppressWarnings("unchecked")
        public Iterator<Appender<ILoggingEvent>> iteratorForAppenders() {
            if (aai == null) {
                return Collections.EMPTY_LIST.iterator();
            }
            return aai.iteratorForAppenders();
        }
    
        public Appender<ILoggingEvent> getAppender(String name) {
            if (aai == null) {
                return null;
            }
            return aai.getAppender(name);
        }
    
        /**
         * Invoke all the appenders of this logger.
         * 
         * @param event
         *          The event to log
         */
        public void callAppenders(ILoggingEvent event) {
            int writes = 0;
            for (Logger l = this; l != null; l = l.parent) {
                writes += l.appendLoopOnAppenders(event);
                if (!l.additive) {
                    break;
                }
            }
            // No appenders in hierarchy
            if (writes == 0) {
                loggerContext.noAppenderDefinedWarning(this);
            }
        }
    
        private int appendLoopOnAppenders(ILoggingEvent event) {
            if (aai != null) {
                return aai.appendLoopOnAppenders(event);
            } else {
                return 0;
            }
        }
    
        /**
         * Remove the appender passed as parameter form the list of appenders.
         */
        public boolean detachAppender(Appender<ILoggingEvent> appender) {
            if (aai == null) {
                return false;
            }
            return aai.detachAppender(appender);
        }
    
        /**
         * Create a child of this logger by suffix, that is, the part of the name
         * extending this logger. For example, if this logger is named "x.y" and the
         * lastPart is "z", then the created child logger will be named "x.y.z".
         * 
         * <p>
         * IMPORTANT: Calls to this method must be within a synchronized block on this
         * logger.
         * 
         * @param lastPart
         *          the suffix (i.e. last part) of the child logger name. This
         *          parameter may not include dots, i.e. the logger separator
         *          character.
         * @return
         */
        Logger createChildByLastNamePart(final String lastPart) {
            int i_index = LoggerNameUtil.getFirstSeparatorIndexOf(lastPart);
            if (i_index != -1) {
                throw new IllegalArgumentException("Child name [" + lastPart + " passed as parameter, may not include [" + CoreConstants.DOT + "]");
            }
    
            if (childrenList == null) {
                childrenList = new CopyOnWriteArrayList<Logger>();
            }
            Logger childLogger;
            if (this.isRootLogger()) {
                childLogger = new Logger(lastPart, this, this.loggerContext);
            } else {
                childLogger = new Logger(name + CoreConstants.DOT + lastPart, this, this.loggerContext);
            }
            childrenList.add(childLogger);
            childLogger.effectiveLevelInt = this.effectiveLevelInt;
            return childLogger;
        }
    
        private void localLevelReset() {
            effectiveLevelInt = Level.DEBUG_INT;
            if (isRootLogger()) {
                level = Level.DEBUG;
            } else {
                level = null;
            }
        }
    
        void recursiveReset() {
            detachAndStopAllAppenders();
            localLevelReset();
            additive = true;
            if (childrenList == null) {
                return;
            }
            for (Logger childLogger : childrenList) {
                childLogger.recursiveReset();
            }
        }
    
        /**
         * The default size of child list arrays. The JDK 1.5 default is 10. We use a
         * smaller value to save a little space.
         */
    
        Logger createChildByName(final String childName) {
            int i_index = LoggerNameUtil.getSeparatorIndexOf(childName, this.name.length() + 1);
            if (i_index != -1) {
                throw new IllegalArgumentException("For logger [" + this.name + "] child name [" + childName
                                + " passed as parameter, may not include '.' after index" + (this.name.length() + 1));
            }
    
            if (childrenList == null) {
                childrenList = new CopyOnWriteArrayList<Logger>();
            }
            Logger childLogger;
            childLogger = new Logger(childName, this, this.loggerContext);
            childrenList.add(childLogger);
            childLogger.effectiveLevelInt = this.effectiveLevelInt;
            return childLogger;
        }
    
        /**
         * The next methods are not merged into one because of the time we gain by not
         * creating a new Object[] with the params. This reduces the cost of not
         * logging by about 20 nanoseconds.
         */
    
        private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
                        final Throwable t) {
    
            final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
    
            if (decision == FilterReply.NEUTRAL) {
                if (effectiveLevelInt > level.levelInt) {
                    return;
                }
            } else if (decision == FilterReply.DENY) {
                return;
            }
    
            buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
        }
    
        private void filterAndLog_1(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param, final Throwable t) {
    
            final FilterReply decision = loggerContext.getTurboFilterChainDecision_1(marker, this, level, msg, param, t);
    
            if (decision == FilterReply.NEUTRAL) {
                if (effectiveLevelInt > level.levelInt) {
                    return;
                }
            } else if (decision == FilterReply.DENY) {
                return;
            }
    
            buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param }, t);
        }
    
        private void filterAndLog_2(final String localFQCN, final Marker marker, final Level level, final String msg, final Object param1, final Object param2,
                        final Throwable t) {
    
            final FilterReply decision = loggerContext.getTurboFilterChainDecision_2(marker, this, level, msg, param1, param2, t);
    
            if (decision == FilterReply.NEUTRAL) {
                if (effectiveLevelInt > level.levelInt) {
                    return;
                }
            } else if (decision == FilterReply.DENY) {
                return;
            }
    
            buildLoggingEventAndAppend(localFQCN, marker, level, msg, new Object[] { param1, param2 }, t);
        }
    
        private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
                        final Throwable t) {
            LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params);
            le.setMarker(marker);
            callAppenders(le);
        }
    
        public void trace(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, null);
        }
    
        public void trace(String format, Object arg) {
            filterAndLog_1(FQCN, null, Level.TRACE, format, arg, null);
        }
    
        public void trace(String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, null, Level.TRACE, format, arg1, arg2, null);
        }
    
        public void trace(String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, format, argArray, null);
        }
    
        public void trace(String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.TRACE, msg, null, t);
        }
    
        public void trace(Marker marker, String msg) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, null);
        }
    
        public void trace(Marker marker, String format, Object arg) {
            filterAndLog_1(FQCN, marker, Level.TRACE, format, arg, null);
        }
    
        public void trace(Marker marker, String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, marker, Level.TRACE, format, arg1, arg2, null);
        }
    
        public void trace(Marker marker, String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, format, argArray, null);
        }
    
        public void trace(Marker marker, String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.TRACE, msg, null, t);
        }
    
        public boolean isDebugEnabled() {
            return isDebugEnabled(null);
        }
    
        public boolean isDebugEnabled(Marker marker) {
            final FilterReply decision = callTurboFilters(marker, Level.DEBUG);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= Level.DEBUG_INT;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }
    
        public void debug(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, null);
        }
    
        public void debug(String format, Object arg) {
            filterAndLog_1(FQCN, null, Level.DEBUG, format, arg, null);
        }
    
        public void debug(String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, null, Level.DEBUG, format, arg1, arg2, null);
        }
    
        public void debug(String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, format, argArray, null);
        }
    
        public void debug(String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.DEBUG, msg, null, t);
        }
    
        public void debug(Marker marker, String msg) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, null);
        }
    
        public void debug(Marker marker, String format, Object arg) {
            filterAndLog_1(FQCN, marker, Level.DEBUG, format, arg, null);
        }
    
        public void debug(Marker marker, String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, marker, Level.DEBUG, format, arg1, arg2, null);
        }
    
        public void debug(Marker marker, String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, format, argArray, null);
        }
    
        public void debug(Marker marker, String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.DEBUG, msg, null, t);
        }
    
        public void error(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, null);
        }
    
        public void error(String format, Object arg) {
            filterAndLog_1(FQCN, null, Level.ERROR, format, arg, null);
        }
    
        public void error(String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, null, Level.ERROR, format, arg1, arg2, null);
        }
    
        public void error(String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, format, argArray, null);
        }
    
        public void error(String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.ERROR, msg, null, t);
        }
    
        public void error(Marker marker, String msg) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, null);
        }
    
        public void error(Marker marker, String format, Object arg) {
            filterAndLog_1(FQCN, marker, Level.ERROR, format, arg, null);
        }
    
        public void error(Marker marker, String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, marker, Level.ERROR, format, arg1, arg2, null);
        }
    
        public void error(Marker marker, String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, format, argArray, null);
        }
    
        public void error(Marker marker, String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.ERROR, msg, null, t);
        }
    
        public boolean isInfoEnabled() {
            return isInfoEnabled(null);
        }
    
        public boolean isInfoEnabled(Marker marker) {
            FilterReply decision = callTurboFilters(marker, Level.INFO);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= Level.INFO_INT;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }
    
        public void info(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
        }
    
        public void info(String format, Object arg) {
            filterAndLog_1(FQCN, null, Level.INFO, format, arg, null);
        }
    
        public void info(String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, null, Level.INFO, format, arg1, arg2, null);
        }
    
        public void info(String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, format, argArray, null);
        }
    
        public void info(String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, t);
        }
    
        public void info(Marker marker, String msg) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, null);
        }
    
        public void info(Marker marker, String format, Object arg) {
            filterAndLog_1(FQCN, marker, Level.INFO, format, arg, null);
        }
    
        public void info(Marker marker, String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, marker, Level.INFO, format, arg1, arg2, null);
        }
    
        public void info(Marker marker, String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, format, argArray, null);
        }
    
        public void info(Marker marker, String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.INFO, msg, null, t);
        }
    
        public boolean isTraceEnabled() {
            return isTraceEnabled(null);
        }
    
        public boolean isTraceEnabled(Marker marker) {
            final FilterReply decision = callTurboFilters(marker, Level.TRACE);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= Level.TRACE_INT;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }
    
        public boolean isErrorEnabled() {
            return isErrorEnabled(null);
        }
    
        public boolean isErrorEnabled(Marker marker) {
            FilterReply decision = callTurboFilters(marker, Level.ERROR);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= Level.ERROR_INT;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }
    
        public boolean isWarnEnabled() {
            return isWarnEnabled(null);
        }
    
        public boolean isWarnEnabled(Marker marker) {
            FilterReply decision = callTurboFilters(marker, Level.WARN);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= Level.WARN_INT;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
    
        }
    
        public boolean isEnabledFor(Marker marker, Level level) {
            FilterReply decision = callTurboFilters(marker, level);
            if (decision == FilterReply.NEUTRAL) {
                return effectiveLevelInt <= level.levelInt;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }
    
        public boolean isEnabledFor(Level level) {
            return isEnabledFor(null, level);
        }
    
        public void warn(String msg) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, null);
        }
    
        public void warn(String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, msg, null, t);
        }
    
        public void warn(String format, Object arg) {
            filterAndLog_1(FQCN, null, Level.WARN, format, arg, null);
        }
    
        public void warn(String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, null, Level.WARN, format, arg1, arg2, null);
        }
    
        public void warn(String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, null, Level.WARN, format, argArray, null);
        }
    
        public void warn(Marker marker, String msg) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, null);
        }
    
        public void warn(Marker marker, String format, Object arg) {
            filterAndLog_1(FQCN, marker, Level.WARN, format, arg, null);
        }
    
        public void warn(Marker marker, String format, Object... argArray) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, format, argArray, null);
        }
    
        public void warn(Marker marker, String format, Object arg1, Object arg2) {
            filterAndLog_2(FQCN, marker, Level.WARN, format, arg1, arg2, null);
        }
    
        public void warn(Marker marker, String msg, Throwable t) {
            filterAndLog_0_Or3Plus(FQCN, marker, Level.WARN, msg, null, t);
        }
    
        public boolean isAdditive() {
            return additive;
        }
    
        public void setAdditive(boolean additive) {
            this.additive = additive;
        }
    
        public String toString() {
            return "Logger[" + name + "]";
        }
    
        /**
         * Method that calls the attached TurboFilter objects based on the logger and
         * the level.
         * 
         * It is used by isYYYEnabled() methods.
         * 
         * It returns the typical FilterReply values: ACCEPT, NEUTRAL or DENY.
         * 
         * @param level
         * @return the reply given by the TurboFilters
         */
        private FilterReply callTurboFilters(Marker marker, Level level) {
            return loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, null, null, null);
        }
    
        /**
         * Return the context for this logger.
         * 
         * @return the context
         */
        public LoggerContext getLoggerContext() {
            return loggerContext;
        }
    
        public void log(Marker marker, String fqcn, int levelInt, String message, Object[] argArray, Throwable t) {
            Level level = Level.fromLocationAwareLoggerInteger(levelInt);
            filterAndLog_0_Or3Plus(fqcn, marker, level, message, argArray, t);
        }
    
        /**
         * Support SLF4J interception during initialization as introduced in SLF4J version 1.7.15
         * @since 1.1.4 
         * @param slf4jEvent
         */
        public void log(org.slf4j.event.LoggingEvent slf4jEvent) {
            Level level = Level.fromLocationAwareLoggerInteger(slf4jEvent.getLevel().toInt());
            filterAndLog_0_Or3Plus(FQCN, slf4jEvent.getMarker(), level, slf4jEvent.getMessage(), slf4jEvent.getArgumentArray(), slf4jEvent.getThrowable());
        }
    
        /**
         * After serialization, the logger instance does not know its LoggerContext.
         * The best we can do here, is to return a logger with the same name
         * returned by org.slf4j.LoggerFactory.
         * 
         * @return Logger instance with the same name
         * @throws ObjectStreamException
         */
        protected Object readResolve() throws ObjectStreamException {
            return LoggerFactory.getLogger(getName());
        }
    }
    logger.class

    博客来源:

    由于使用的版本较高,本文稍有不同,新版本中也见到很多新的编程思想

    读logback源码系列文章(四)——记录日志
  • 相关阅读:
    Apple Watch知识点总结
    segue场景跳转的使用总结
    iOS地图相关知识点总结
    第三方库AFNetwork的作用和用法详解
    UIImagePickerController的知识点总结
    关于图片的压缩问题
    盒子模型知识
    CSS3新增属性
    ps命令详解
    http请求中的Referer的作用
  • 原文地址:https://www.cnblogs.com/lzghyh/p/14912014.html
Copyright © 2020-2023  润新知