Logback中使用TurboFilter

在Java开发中,底层框架抛异常时会产生重复错误日志,对接告警会重复告警。修改源码不可取,使用Logback时,TurboFilter可解决该问题。它与日志上下文绑定,能过滤所有日志请求。通过继承类重写方法可动态修改日志,还需在配置中添加相应设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可能看到这个标题,读者会问:要修改日志的级别,不是直接修改log.xxx就好了吗?为何要搞那么复杂呢?所以,先说一下场景,为什么要通过TurboFilter去动态的修改日志级别。我们在使用Java开发各种项目的时候必然的会引入很多框架,这些框架通过堆叠的方式完成所要提供的业务服务(一个服务请求在进入后会在这些框架中兜一圈,然后返回结果),当一个比较底层的框架在处理过程中抛出了异常之后,这个异常会不断的向上传递。这个时候,有的框架直接throw,继续向上抛,而有的在throw之前还会自己打印一下error日志,这就导致了当出现异常的时候,往往会出现一连串类似的错误日志记录。如果对接了错误日志告警,就会出现重复告警的现象。为了解决类似这样的问题,修改源码重新编译最直接,但是不可取。所以希望可以有更好的手段去控制这些已经被编码固化的日志打印信息。当我们使用Logback的时候,TurboFilter就是解决该问题的工具之一。

TurboFIlter不同于之前在[《Logback中如何自定义灵活的日志过滤规则》]一文中介绍的那些通过ch.qos.logback.core.filter.Filter接口实现的过滤器。ch.qos.logback.core.filter.Filter实现的过滤器是与Appender绑定的,而TurboFIlter是与日志上下文绑定的,它会过滤所有的日志请求,并且TurboFIlter的方法中提供了丰富的可访问信息用来进行控制和改写。

比如下面的实现,通过继承ch.qos.logback.classic.turbo.TurboFilter类,并重写decide方法,将org.springframework.cloud.sleuth.instrument.web.ExceptionLoggingFilter类中原本要打印的ERROR日志DENY掉(过滤掉),同时以WARN级别打印一封相同的内容,这样就实现了对已定义日志的动态修改。

public class ForceWarnFilter extends TurboFilter {

    @Override
    public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable throwable) {
        if (level == Level.ERROR && logger.getName().equals("org.springframework.cloud.sleuth.instrument.web.ExceptionLoggingFilter")) {
            logger.warn(marker, format, params);
            return FilterReply.DENY;
        }
        return FilterReply.NEUTRAL;
    }

}

为了让上面定义的过滤器生效,需要在logback的配置xml中增加如下配置:

<configuration>
    <turboFilter class="com.didispace.log.filter.ForceWarnFilter" />

    ......
</configuration>

或者也可以在应用主类中增加:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.addTurboFilter(new MyTurboFilter());

更多关于Logback过滤器的内容可参考官方文档:https://logback.qos.ch/manual/filters.html

参考源码解读:http://skyao.github.io/2014/09/11/logback-process/

<think>首先,用户的问题是关于如何在logback使用MarkerFilter的。用户提供了系统级指令,我必须遵守这些指令: 1. 所有行内数学表达式必须使用$...$格式。例如,$x^2$。 2. 独立公式必须使用$$...$$格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 此外,在用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 用户还提供了三个引用,这些是关于logback的MarkerFilter的。引用[1]描述了MarkerFilter的基本用法,引用[2]给出了配置示例,引用[3]讨论了过滤器的一般结构。我应该参考这些来回答问题。 用户的问题是:“我想了解如何在logback使用MarkerFilter 请问logback MarkerFilter 使用方法及示例” 所以,我的回答需要包括: 1. 解释MarkerFilter是什么。 2. 提供使用方法和示例。 3. 结构清晰,逐步引导。 4. 最后生成相关问题。 步骤: 1. **介绍MarkerFilter**:基于引用[1],MarkerFilter用于支持slf4j的Marker,通过MarkerFactory.getMarker获取marker,并在配置文件中配置。 2. **使用方法**:从引用[2]中,我可以提取配置示例。例如,定义过滤器,设置onMatch和onMismatch行为。 3. **示例**:提供一个logback.xml配置文件的示例,展示如何添加MarkerFilter。 4. **代码示例**:如果需要,可以展示Java代码中如何使用marker。 5. **引用**:在回答中自然地添加引用标识。例如,当提到配置时,添加[^2]。 6. **生成相关问题**:在最后,添加“§§相关问题§§”部分,列出相关问题。 确保回答用中文。 结构大纲: - **开头**:简要介绍MarkerFilter。 - **步骤1**:解释MarkerFilter的作用。 - **步骤2**:描述配置方法。 - **步骤3**:提供配置文件示例。 - **步骤4**:可能添加Java代码示例。 - **结尾**:总结或注意事项。 - **相关问题**:生成2-3个相关问题。 引用处理: - 引用[1]:聊聊logback的MarkerFilter,提到基本用法。 - 引用[2]:解锁新技能,提供配置示例。 - 引用[3]:常规过滤器继承Filter类,但用户问题具体是MarkerFilter,所以可能不直接相关,但可以提及。 在回答中,当引用信息时,添加[^1], [^2]等。 例如:“MarkerFilter可以通过MarkerFactory.getMarker获取marker[^1]。” 最后,生成相关问题,如: 1. MarkerFilter与其他过滤器有什么区别? 2. 如何动态添加MarkerFilter? 3. MarkerFilter在日志管理中的实际应用场景? 确保没有数学表达式,因为用户问题是关于logback的,不涉及数学。但指令说所有行内数学表达式必须用$...$,但在这个上下文中可能不需要。所以,我可以忽略数学部分,除非必要。 完整回答: - 用中文。 - 结构:先解释,然后方法,示例,相关问题。</think>### logback MarkerFilter 使用方法及示例 MarkerFilter 是 logback 提供的一个过滤器,用于基于 SLF4J 的 Marker 接口来过滤日志事件。Marker 允许您为日志添加自定义标记(例如,用于区分业务日志或错误类型),MarkerFilter 则通过配置文件定义对这些标记的处理规则(如接受或拒绝特定标记的日志)。这在日志分类和精细化控制中非常有用。下面我将逐步解释使用方法,并提供详细示例。参考引用信息,我将确保回答可靠,并基于 logback 官方文档和社区实践[^1][^2]。 #### 步骤 1: 理解 MarkerFilter 的基本概念 - **Marker 是什么?** Marker 是 SLF4J 提供的一个接口,用于为日志添加额外标记(例如,标识敏感操作或特定模块)。您可以通过 `MarkerFactory.getMarker("markerName")` 创建 Marker[^1]。 - **MarkerFilter 的作用** MarkerFilter 继承自 logback 的 `TurboFilter`,它根据日志事件的 Marker 值进行过滤。在配置文件中,您可以设置: - `onMatch`:当 Marker 匹配时如何处理(例如,`ACCEPT` 接受日志,`DENY` 拒绝日志)。 - `onMismatch`:当 Marker 不匹配时如何处理(例如,`NEUTRAL` 表示不干预,交由其他过滤器决定)[^1][^2]。 这允许您实现精细的日志路由,例如只记录带有特定标记的日志到文件。 #### 步骤 2: 配置 MarkerFilter 的方法 在 logback 的配置文件(通常是 `logback.xml`)中添加 MarkerFilter。以下是关键步骤: 1. **定义 MarkerFilter**:在 `<configuration>` 标签内,使用 `<turboFilter>` 元素定义 MarkerFilter。 2. **设置参数**: - `class`:指定过滤器类为 `ch.qos.logback.classic.turbo.MarkerFilter`。 - `marker`:指定要匹配的 Marker 名称(例如,`"SECURITY"`)。 - `onMatch` 和 `onMismatch`:设置过滤行为,值可以是 `ACCEPT`, `DENY`, 或 `NEUTRAL`。 3. **添加到上下文**:MarkerFilter 会自动注册到 logback 的 LoggerContext 中,无需额外代码[^2]。 注意:MarkerFilter 是 TurboFilter 的一种,与常规过滤器(如 `LevelFilter`)不同,它作用于日志事件早期阶段,效率更高[^3]。 #### 步骤 3: 完整示例 下面是一个实际示例,展示如何在 `logback.xml` 中配置 MarkerFilter,并结合 Java 代码使用。假设我们有两个 Marker:`"AUDIT"`(用于审计日志)和 `"DEBUG"`(用于调试日志),我们只希望记录 `"AUDIT"` 标记的日志到文件,拒绝 `"DEBUG"` 标记的日志。 ##### 配置文件示例 (`logback.xml`) ```xml <configuration> <!-- 定义 MarkerFilter:接受 "AUDIT" 标记的日志 --> <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter"> <marker>AUDIT</marker> <onMatch>ACCEPT</onMatch> <!-- 匹配时接受日志 --> <onMismatch>NEUTRAL</onMismatch> <!-- 不匹配时不干预 --> </turboFilter> <!-- 定义另一个 MarkerFilter:拒绝 "DEBUG" 标记的日志 --> <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter"> <marker>DEBUG</marker> <onMatch>DENY</onMatch> <!-- 匹配时拒绝日志 --> <onMismatch>NEUTRAL</onMismatch> </turboFilter> <!-- 配置 Appender(例如,文件输出) --> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>application.log</file> <encoder> <pattern>%date %level [%marker] - %msg%n</pattern> </encoder> </appender> <!-- 设置根 Logger,使用上述 Appender --> <root level="INFO"> <appender-ref ref="FILE" /> </root> </configuration> ``` **解释**: - 第一个 MarkerFilter 接受带有 `"AUDIT"` 标记的日志(`onMatch: ACCEPT`),其他日志由后续过滤器处理。 - 第二个 MarkerFilter 拒绝带有 `"DEBUG"` 标记的日志(`onMatch: DENY`),防止它们被记录。 - 在日志输出中,`%marker` 在 pattern 中显示 Marker 名称,便于调试[^2]。 ##### Java 代码示例 在应用程序中,使用 SLF4J 的 Logger 和 MarkerFactory 添加标记: ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Marker; import org.slf4j.MarkerFactory; public class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); // 创建 Marker private static final Marker AUDIT_MARKER = MarkerFactory.getMarker("AUDIT"); private static final Marker DEBUG_MARKER = MarkerFactory.getMarker("DEBUG"); public static void main(String[] args) { // 记录带有 AUDIT 标记的日志(会被接受并记录到文件) logger.info(AUDIT_MARKER, "这是一条审计日志。"); // 记录带有 DEBUG 标记的日志(会被拒绝,不记录) logger.debug(DEBUG_MARKER, "这是一条调试日志,不会出现在文件中。"); // 记录无标记的日志(根据 onMismatch 设置,可能被记录) logger.info("普通日志,可能被记录。"); } } ``` **运行结果**: - 文件 `application.log` 中只包含 `AUDIT` 标记的日志和普通日志(如果 `onMismatch` 允许)。 - `DEBUG` 标记的日志被过滤掉,不会输出[^1][^2]。 #### 注意事项 - **性能影响**:MarkerFilter 是高效的,但过多过滤器可能轻微增加日志处理时间。建议在需要精细控制时使用。 - **错误处理**:如果 Marker 名称在配置文件中拼写错误,logback 会忽略该过滤器(不会抛出异常),需检查日志输出。 - **与其他过滤器结合**:MarkerFilter 可以与 `LevelFilter` 等组合使用,实现更复杂的规则(例如,只记录 ERROR 级别且带有特定标记的日志)[^3]。 通过以上步骤,您可以灵活地在 logback使用 MarkerFilter 来管理日志。如果您在测试中遇到问题,建议查看 logback 官方文档或调试日志上下文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值