• logback源码阅读-Logger日志生成(三)


    类图

     Logger实现了slf4J提供的Logger接口实现,ch.qos.logback.classic.Logger

    成员变量

    //当前logger的name
        private String name;
        //当前logger的等级
        private transient Level level;
        //level对应的int数值
        private transient int effectiveLevelInt;
        //logger的父logger
        private transient Logger parent;
        //logger的子logger
        private transient List<Logger> childrenList;
        //appder负责日志的输出源 如 数据库 es 控制台
        private transient AppenderAttachableImpl<ILoggingEvent> aai;
        private transient boolean additive = true;
        //loggerContext 全局只有一个 创建时通过Binder获取注入进来的
        final transient LoggerContext loggerContext;

    核心方法

    isInfo

    isRootLogger

    是否是根logger

        private boolean isRootLogger() {
            return this.parent == null;
        }

    setLevel

     public synchronized void setLevel(Level newLevel) {
            //判断是否有改变level
            if (this.level != newLevel) {
                //root不允许改level
                if (newLevel == null && this.isRootLogger()) {
                    throw new IllegalArgumentException("The level of the root logger cannot be set to null");
                } else {
                    //改变当前logger的level
                    this.level = newLevel;
                    //如果传入的是空 则从父logger继承
                    if (newLevel == null) {
                        this.effectiveLevelInt = this.parent.effectiveLevelInt;
                        newLevel = this.parent.getEffectiveLevel();
                    } else {
                        //levelInt
                        this.effectiveLevelInt = newLevel.levelInt;
                    }
                    //如果有子Logger子logger的一起改变
                    if (this.childrenList != null) {
                        int len = this.childrenList.size();
    
                        for(int i = 0; i < len; ++i) {
                            Logger child = (Logger)this.childrenList.get(i);
                            child.handleParentLevelChange(this.effectiveLevelInt);
                        }
                    }
                    //<2>触发loggerContext监听器改变通知LoggerContextListener.onLevelChange
                    this.loggerContext.fireOnLevelChange(this, newLevel);
                }
            }
        }

    filterAndLog_0_Or3Plus

    我们调用info debug方法单个参数String都是进入此方法

    ch.qos.logback.classic.Logge#info(String str)r#filterAndLog_0_Or3Plus

      private void filterAndLog_0_Or3Plus(String localFQCN, Marker marker, Level level, String msg, Object[] params, Throwable t) {
            /**
             * <1>根据loggerContext TurboFilterList执行日志过滤器 用于过滤此日志是否放行默认返回NEUTRAL走日志级别比较
             * DENY为拒绝
             *ACCEPT为放行
             */
            FilterReply decision = this.loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
            if (decision == FilterReply.NEUTRAL) {
                if (this.effectiveLevelInt > level.levelInt) {
                    return;
                }
            } else if (decision == FilterReply.DENY) {
                return;
            }
            //<4>
            this.buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
        }

    <1>使用方式

    /**
     * @author liqiang
     * @date 2020/1/7 14:43
     * @Description:
     */
    public class ContentTurboFilter extends TurboFilter {
        @Override
        public FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects, Throwable throwable) {
            if(s==null||s=="忽略"){//内容等于忽略的全部忽略
                return FilterReply.DENY;
            }else if(s=="放行"){//日志内容等于放行则全部放行
                return FilterReply.ACCEPT;
            }
            //否则走正常日志级别过滤
            return FilterReply.NEUTRAL;
        }
    }
    <configuration>
        <turboFilter class="com.liqiang.logbacktest.filter.ContentTurboFilter" />
    ....
    </configuration>

    或者

    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    lc.addTurboFilter(new ContentTurboFilter());

    <1>getTurboFilterChainDecision_0_3OrMore

    ch.qos.logback.classic.LoggerContext#getTurboFilterChainDecision_0_3OrMore

     final FilterReply getTurboFilterChainDecision_0_3OrMore(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
            //是否有配置过滤器 如果配置走过滤逻辑<2>
            return this.turboFilterList.size() == 0 ? FilterReply.NEUTRAL : this.turboFilterList.getTurboFilterChainDecision(marker, logger, level, format, params, t);
        }

    <2>getTurboFilterChainDecision

    ch.qos.logback.classic.spi.TurboFilterList#getTurboFilterChainDecision

        public FilterReply getTurboFilterChainDecision(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
                int size = this.size();
                if (size == 1) {
                    try {
                        //如果只配置了一个过滤器
                        TurboFilter tf = (TurboFilter)this.get(0);
                        //执行过滤逻辑
                        return tf.decide(marker, logger, level, format, params, t);
                    } catch (IndexOutOfBoundsException var13) {
                        //发生异常走日志级别控制
                        return FilterReply.NEUTRAL;
                    }
                } else {
                    Object[] tfa = this.toArray();
                    int len = tfa.length;
                    //遍历过滤器
                    for(int i = 0; i < len; ++i) {
                        TurboFilter tf = (TurboFilter)tfa[i];
                        FilterReply r = tf.decide(marker, logger, level, format, params, t);
                        //当任意一个返回放行或者拒绝直接返回
                        if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {
                            return r;
                        }
                    }
    
                    return FilterReply.NEUTRAL;
                }
        }

    <4>buildLoggingEventAndAppend

    ch.qos.logback.classic.Logge#info(String str)r#filterAndLog_0_Or3Plus#buildLoggingEventAndAppend

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

    创建LoggingEvent对象 该类实现了slf4j LoggingEvent接口

    <1>

    <5>callAppenders

    ch.qos.logback.classic.Logge#info(String str)r#filterAndLog_0_Or3Plus#buildLoggingEventAndAppend#callAppenders

     public void callAppenders(ILoggingEvent event) {
    
            //记录写的数量
            int writes = 0;
            /**
             * 从当前logger.AppenderAttachableImpl 往父类遍历
             * 直到遇到父logger终止additive为fasle  根logger是root
             * 如果父logger子logger都有相同的appender 就会重复记录
             */
            for(Logger l = this; l != null; l = l.parent) {
                //没写一次writes+
                writes += l.appendLoopOnAppenders(event);
                if (!l.additive) {
                    break;
                }
            }
            //如果写的次数是0  触发警告日志打印
            if (writes == 0) {
                this.loggerContext.noAppenderDefinedWarning(this);
            }
    
        }
        private int appendLoopOnAppenders(ILoggingEvent event) {
            //aai为  private transient AppenderAttachableImpl<ILoggingEvent> aai;
            return this.aai != null ? this.aai.appendLoopOnAppenders(event) : 0;
        }

    isInfo

    public boolean isInfoEnabled(Marker marker) {
            //这里跟上面一样也会走TurboFilterList
            FilterReply decision = this.callTurboFilters(marker, Level.INFO);
            if (decision == FilterReply.NEUTRAL) {
                return this.effectiveLevelInt <= 20000;
            } else if (decision == FilterReply.DENY) {
                return false;
            } else if (decision == FilterReply.ACCEPT) {
                return true;
            } else {
                throw new IllegalStateException("Unknown FilterReply value: " + decision);
            }
        }

    总结

    1.info都会先走TurboFilter 走过滤

    2.TurboFilter过滤通过后才会创建Event对象

    3.最终通过Logger的发以及所有父类的AppenderAttachableImpl进行输出

    思路

    1.必须我们现在现有系统中如果放开info日志会大量打印,很多地方为了方便排查问题都打印了入参和出参。其实很多时候我们都不是很需要

    2.可以通过TurboFilter 实现在通过redis或者数据库动态修改日志级别

  • 相关阅读:
    文化课随笔
    微积分与无穷级数
    [康复计划]-数论基础
    [Codeforces]CF742(Div.2)A-E
    第一次个人编程作业的过程和想法
    第一次个人编程作业
    Python命令行参数及文件读出写入
    第一次个人编程作业
    第一次个人编程作业
    第一次博客作业
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12161200.html
Copyright © 2020-2023  润新知