You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java应用中用Log4j和SLF4J过滤重复日志消息?

解决Log4j过滤重复日志消息的方案

Log4j本身没有内置的重复日志过滤组件,但可以通过自定义过滤器实现高效去重,同时满足你简化配置、兼容多Appender的需求。以下是具体实现方案:

一、自定义重复日志过滤器

1. 实现Filter类

编写一个Log4j插件式过滤器,通过记录每条日志的最后输出时间,过滤超时范围内的重复消息(可配置超时时间,避免误过滤不同场景的相同日志):

import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.filter.AbstractFilter;

import java.util.concurrent.ConcurrentHashMap;

@Plugin(name = "DuplicateMessageFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
public class DuplicateMessageFilter extends AbstractFilter {

    private final ConcurrentHashMap<String, Long> lastLoggedRecords = new ConcurrentHashMap<>();
    private final long timeoutMillis;

    private DuplicateMessageFilter(long timeoutMillis, Result onMatch, Result onMismatch) {
        super(onMatch, onMismatch);
        this.timeoutMillis = timeoutMillis;
    }

    @Override
    public Result filter(LogEvent event) {
        String formattedMsg = event.getMessage().getFormattedMessage();
        long now = System.currentTimeMillis();

        Long lastTime = lastLoggedRecords.get(formattedMsg);
        if (lastTime != null && (now - lastTime) < timeoutMillis) {
            return onMatch; // 重复消息,执行过滤
        }

        lastLoggedRecords.put(formattedMsg, now);
        return onMismatch; // 非重复消息,允许输出
    }

    @PluginFactory
    public static DuplicateMessageFilter createFilter(
            @PluginAttribute(value = "timeoutMillis", defaultLong = 300000) long timeoutMillis,
            @PluginAttribute(value = "onMatch", defaultString = "DENY") Result onMatch,
            @PluginAttribute(value = "onMismatch", defaultString = "ACCEPT") Result onMismatch) {
        return new DuplicateMessageFilter(timeoutMillis, onMatch, onMismatch);
    }
}

2. 配置log4j.xml

将自定义过滤器添加到需要去重的Appender中(比如ConsoleAppender),配置简单且可复用至其他Appender:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <!-- 自定义重复消息过滤器:超时5分钟,重复则拒绝输出 -->
            <DuplicateMessageFilter timeoutMillis="300000" onMatch="DENY" onMismatch="ACCEPT"/>
        </Console>
        <!-- 后续扩展其他Appender时,直接添加该过滤器即可 -->
        <!-- <File name="File" fileName="app.log">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            <DuplicateMessageFilter timeoutMillis="300000"/>
        </File> -->
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

二、关键配置说明

  • timeoutMillis:设置重复消息的判断超时时间,默认5分钟。如果需要严格过滤连续重复的日志(比如循环中重复输出的同一条日志),可将值设为0,但可能会误过滤不同时间点的相同业务日志,建议根据实际场景调整。
  • onMatch:重复消息的处理策略,设为DENY即过滤重复日志;onMismatch设为ACCEPT即允许非重复日志输出。
  • 多Appender兼容:后续新增的Appender只需添加<DuplicateMessageFilter>标签即可实现去重,无需额外修改逻辑。

内容的提问来源于stack exchange,提问作者aj.savvi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:32:10