类图
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或者数据库动态修改日志级别