如何让log4j2自定义Filter对象在上下文全局范围生效?
问题根本原因
这个问题是log4j2的性能优化机制导致的,不属于框架缺陷,具体逻辑如下:
- log4j2为了降低无效日志生成的性能开销,对
logger.debug()/logger.info()等日志打印调用做了快速校验优化:默认会先判断当前Logger的配置级别是否匹配本次打印的级别,如果不匹配直接返回false,不会生成完整的LogEvent对象,也不会走全局过滤器链的逻辑。 - 内置的
ThresholdFilter属于log4j2核心级别的过滤器,实现了LevelFilterSupport标记接口,框架启动时会识别到这类和日志级别相关的全局过滤器,自动调整快速校验逻辑,不会直接用Logger级别做拦截,所以就算Root级别是INFO,debug级别的日志调用也会走到全局过滤器的逻辑里。 - 你自定义的过滤器没有实现
LevelFilterSupport接口,框架默认认为你的过滤器和日志级别判断无关,因此保留快速校验逻辑:Root级别配置为INFO时,logger.debug()调用会在快速校验阶段直接被拦截,根本不会走到全局过滤器的filter方法,所以你看不到调用记录。 - 过滤器放在Logger节点下能生效,是因为框架检测到指定Logger下配置了自定义过滤器时,会自动跳过该Logger的快速级别校验,所有日志调用都会走过滤器链逻辑。
如果你使用的log4j2版本低于2.12.0,不存在
LevelFilterSupport接口,直接使用下方方案2即可。
两种解决方案
方案1:实现LevelFilterSupport接口(推荐)
给你的ThresholdFilterCustom类补充实现LevelFilterSupport接口,重写getLevel()方法返回你配置的级别即可,修改后的核心代码如下:
import org.apache.logging.log4j.core.filter.LevelFilterSupport; // 新增导入 // 补充实现LevelFilterSupport接口 @Plugin(name = "ThresholdFilterCustom", category = "Core", elementType = "filter", printObject = true) public final class ThresholdFilterCustom extends AbstractFilter implements LevelFilterSupport<ThresholdFilterCustom> { private final Level level; // 原有代码保持不变... // 新增getLevel方法 @Override public Level getLevel() { return this.level; } }
修改后框架就会识别到你的全局过滤器属于级别相关过滤器,会跳过快速级别校验,你的filter方法就能被正常调用。
方案2:调整Root级别为最低需要的级别
如果你不想修改自定义过滤器的代码,可以直接把log4j2.xml里的Root级别调整为你需要放行的最低级别,比如你需要过滤DEBUG级别的日志,就把Root的level改成DEBUG:
<Root level="DEBUG"> <AppenderRef ref="Console" /> </Root>
这样快速校验阶段logger.debug()调用会直接通过,生成LogEvent后就会走到你的全局过滤器逻辑里,由你自定义的过滤器决定是否放行。
内容的提问来源于stack exchange,提问作者QQs
相关产品推荐
相关产品推荐

