作为框架必备的基本组件之一的Filter,在log4j2中同样存在并处于相当重要的地位。本文我们将对其执行逻辑,继承体系等等进行一番简单的探索,意图找出一个动态筛选日志信息的优化需求的解决方案。
在平时的开发过程中,我们一般都会选择将将日志级别设定为DEBUG甚至更低,这样当出现问题时可以知晓更多,更详细的信息,方便问题的排查;但万事有利必有弊,详细也意味着繁琐,大量嘈杂的日志信息可能会将你真正关注的日志内容淹没掉,加大查找难度。因此最近同事提出了一个动态筛选日志信息的优化需求让我十分感兴趣。
类似的需求,最容易想到的简单方法就是在进行日志输出时,谨慎选择甚至自定义日志级别,但是考虑到框架里的日志级别不受控制,随意自定义日志级别徒劳增加开发人员的记忆负担等等缺陷,这个想法在出现的瞬间基本就被判了死刑。
通过查阅log4j2官网,最终发现其提供的Filter机制应该是能够满足本次需求的。这里贴一下官网对Filter的介绍:
1. Filters allow Log Events to be evaluated to determine if or how they should be published.
2. A Filter will be called on one of its filter methods and will return a Result, which is an Enum that has one of 3 values - ACCEPT, DENY or NEUTRAL.
log4j2中的Filter可以配置在四个位置,由全局到局部依次是 Context-wide,Logger ,Appender ,Appender Reference。下面给出一个具体的配置示例代码:
<Configuration status="TRACE" monitorInterval="5" packages="com.kanq.extend.cat.log4j2">
<Filters>
<!-- 全局级别Filter -->
<LevelRangeFilter minLevel="DEBUG" maxLevel="ERROR" onMatch="DENY"></LevelRangeFilter>
</Filters>
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
<!-- Appender级别的Filter -->
<BurstFilter level="INFO" rate="16" maxBurst="100"/>
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<!-- Logger级别的Filter -->
<Root level="error">
<MapFilter onMatch="ACCEPT" onMismatch="NEUTRAL" operator="or">
<KeyValuePair key="eventId" value="Login"/>
<KeyValuePair key="eventId" value="Logout"/>
</MapFilter>
</Root>
<Logger name="TestJavaScriptFilter" level="trace" additivity="false">
<!-- AppenderRef级别的Filter -->
<AppenderRef ref="List">
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
<ScriptRef ref="filter.js" />
</ScriptFilter>
</AppenderRef>
</Logger>
</Loggers>
</Configuration>
这里贴一下在单元测试下的log4j2调用执行堆栈图(对应的配置文件是上面配置中的全局级别Filter)。
从以上堆栈图中,我们大致可以得到如下信息:
借用下面引用链接中的一张图来描述,大概就是如下这样:
最后让我们来看看Filter的继承体系。
通过IDE提供的类层次结构图可以看到,可以说是非常标准的继承实现方式了, 契约接口 —— 骨架抽象类 —— 具体实现类 —— 组合模式。
下面就让我们挑选出一些比较典型的Filter进行简单地分析:
minLevel
,maxLevel
的配置;其和我们的思维惯式有着些许的差异,可能会造成困扰。**细节之处可以查看StandardLevel
中各个日志级别的底层数值,以及Level.isInRange
的比较逻辑。概括而言就是 底层支撑的数值越小,日志危险级别越高。也就是我们如果想要只保留WARN到ERROR级别的日志,那么应该如下配置:<!-- 危险级别高的等级配置 作为minLevel的值 -->
<LevelRangeFilter minLevel="ERROR" maxLevel="WARN"
onMatch="ACCEPT">
</LevelRangeFilter>
```
<Filters>
必须放在<properties>
节点之后。 否则会出现意料不到的问题。例如本人碰到的就是 <PatternLayout pattern="${pattern_debug_info_warn}" />
替换失败。版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/lqzkcx3/article/details/81806076
内容来源于网络,如有侵权,请联系作者删除!