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;aai就是所有appender的管理类 负责遍历输出appender 直通车
        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触发 logger的AppenderAttachableImpl进行输出

思路

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

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

 

posted @ 2020-01-07 14:09  意犹未尽  阅读(912)  评论(0编辑  收藏  举报