第七章节介绍Filter(过滤器),它不是必备的核心对象,但是在某些业务场景下需要使用Filter。
Logback的Filter分为两种类型,TurboFilters和Appender绑定的Filter。TurboFilter的执行顺序在Appender Filter之前,此时还未创建出ILoggingEvent,所以可以过滤的条件有限。
每种Filter都可以扩展,实现自定义的Filter,当然日志框架本身也内置一些Filter类型。
本章的内容分为以下两个部分
- 介绍Appender的Filter,内置和自定义两种方式
- 介绍TurboFilter,内置和自定义两种方式。
在本文中只有logback-classic模块相关的内容,logback-access模块的内容未提及。
1、Appender Filter
在开始之前,首先需要了解抽象类Filter,它有一个核心方法decide,参数为ILoggingEvent,返回值为FilterReply枚举类,当为DENY时,抛弃请求,当为NEUTRAL时,继续执行下一个过滤器,当为ACCEPT时,跳过所有的过滤器。
1.1 自定义
实现自定义Appender Filter的步骤如下:
- 编写MyFilter继承Filter抽象类。实现decide逻辑。
- 将MyFilter与Appender绑定。
示例代码如下:
MyFilter
public class MyFilter extends Filter<ILoggingEvent> { @Override public FilterReply decide(ILoggingEvent event) { // 如果loggerName 中存在 test,忽略这些日志信息 if (event.getLoggerName().toUpperCase().contains("TEST")) { return FilterReply.DENY; } return FilterReply.DENY; } }
配置
<!-- 配置ConsoleAppender --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!-- 注册myFilter --> <filter class="learn.logback.chapter7.MyFilter"/> <encoder> <pattern>${default_pattern}</pattern> </encoder> </appender>
1.2 内置
1.2.1 LevelFilter
当logging request的日志级别与levelFilter中配置的日志级别相等时,符合过滤器条件,反之亦然。
它的配置如下
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!-- 配置levelFilter --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>NEUTRAL</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern>${default_pattern}</pattern> </encoder> </appender>
1.2.2 ThresholdFilter
当logging request的日志级别大于等于配置中的日志级别时,符合过滤器条件,反之亦然。
它的配置如下:
<!-- 配置ConsoleAppender --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!-- 配置ThresholdFilter --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern>${default_pattern}</pattern> </encoder> </appender>
1.2.3 EvaluatorFilter
在原著中提及两种EvaluatorFilter,一种是GEventEvaluatorFilter,它需要在配置文件中添加Groovy表达式作为过滤条件,另外一种是JaninoEventEvaluator,它需要在配置文件中添加Java代码作为过滤条件。
首先不建议在配置文件中夹杂其他语言的语法,不论是Groovy还是Java。
其次是EvaluatorFilter它实现的功能,其他过滤器也可以实现。
这样做可以避免在配置文件中夹杂其他语言的语法,使得配置文件更简洁,更方便阅读和维护。
2、TurboFilter
在第二章核心流程部分,第一步就是执行TurboFilters,此时ILoggingEvent对象还未创建,所能过滤的信息都来源与LoggerContext,Marker等等。过滤条件没有Appender Filter丰富。
2.1 自定义
与Appender Filter的步骤相同,也是两步,自定义MyTurboFilter,添加配置。
public class MyTurboFilter extends TurboFilter { private String testMarkerStr; private Marker testMarker; @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { if (!isStarted()) { return FilterReply.NEUTRAL; } // Marker对象重写了equals方法,Marker相等只需要Marker的name属性相等 if ((testMarker.equals(marker))) { return FilterReply.NEUTRAL; } else { return FilterReply.DENY; } } public String getTestMarkerStr() { return testMarkerStr; } public void setTestMarkerStr(String testMarkerStr) { this.testMarkerStr = testMarkerStr; } // 每一种日志框架的核心对象都有生命周期的概念,在使用前必须确保已经start @Override public void start() { if (testMarkerStr != null && testMarkerStr.length() != 0) { // 将字符串转换为Marker对象 testMarker = MarkerFactory.getMarker(testMarkerStr); super.start(); } } }
配置文件
<turboFilter class="learn.logback.chapter7.MyTurboFilter"> <Marker>sample</Marker> </turboFilter>
与Appender Filter的不同之处在于:
- 它是配置在Configuration子标签之下的,而Appender Filter配置在Appender子标签之下。
- 它是影响所有日志请求的,Appender Filter只会影响终端为当前Appender的日志请求。
- 它的执行顺序在ILoggingEvent对象之前,而Appender Filter在ILoggingEvent对象创建之后。
- 它的可过滤的条件比Appender Filter少。例如它无法收集到Thread线程的信息,无法收集到日期的信息,而后者都可以。
2.2 内置
2.2.1 MDCTurboFilter
MDCTurboFilter根据MDC中的变量进行过滤,首先检查变量是否存在,其次检查变量的值是否与配置的值相等。
<turboFilter class="ch.qos.logback.classic.turbo.MDCFilter"> <MDCKey>username</MDCKey> <Value>test</Value> <OnMatch>ACCEPT</OnMatch> <OnMismatch>DENY</OnMismatch> </turboFilter>
例如本示例中只输出test用户的日志。
2.2.2 MarkerFilter
MarkerFilter根据日志请求携带的标记进行过滤,检查二者的Marker对象是否相等,即name属性是否相等
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter"> <Marker>Important</Marker> <OnMatch>DENY</OnMatch> </turboFilter>
本示例中只输出携带Important标记的日志请求。
2.2.3 DuplicateMessageFilter
DuplicateMessageFilter根据日志信息的重复次数进行过滤。日志信息重复的判断条件有:
- 非参数化情形下,日志信息完全相同。即日志信息中不包含{}。
- 参数化情况下,日志信息相同,包含的{}个数和位置相同,参数的值可以不同。
它的AllowedRepetitions代表可以重复的次数,默认值为5。
需要注意的是日志信息第一次出现,第二次出现表示第一次重复的含义,所以当设置为5时,总共包含日志信息本身和5次重复信息,总共是6次。
<turboFilter class="ch.qos.logback.classic.turbo.DuplicateMessageFilter"> <!-- 最多重复3次 --> <AllowedRepetitions>3</AllowedRepetitions> </turboFilter>