zoukankan      html  css  js  c++  java
  • 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或者数据库动态修改日志级别

  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12161200.html
Copyright © 2011-2022 走看看