能否配置/扩展log4net以停止长时间故障时重复记录相同异常?
解决log4net重复日志刷屏问题(无需修改业务异常捕获代码)
Hey Juan,针对你遇到的外部服务/Token服务故障时日志疯狂刷屏、15分钟就触发配额超限的问题,咱们完全不用改动C#业务代码,直接在log4net的配置和扩展层面就能搞定,下面给你几个实用方案:
1. 自定义重复日志过滤Filter
核心思路是给log4net加一个过滤器,短时间内相同内容的日志只输出一次,直接把重复日志拦在Appender处理之前。
具体操作:
先写一个轻量的自定义Filter类(这个属于日志组件层,不算业务代码改动):
public class DuplicateLogFilter : FilterSkeleton { // 用线程安全字典存储每条日志的最后输出时间 private readonly ConcurrentDictionary<string, DateTime> _lastLoggedEntries = new ConcurrentDictionary<string, DateTime>(); // 可配置的重复拦截间隔,默认60秒 public int BlockIntervalSeconds { get; set; } = 60; public override FilterDecision Decide(LoggingEvent loggingEvent) { var logContent = loggingEvent.RenderedMessage; if (_lastLoggedEntries.TryGetValue(logContent, out var lastLogTime) && DateTime.Now - lastLogTime <= TimeSpan.FromSeconds(BlockIntervalSeconds)) { return FilterDecision.Deny; // 拒绝这条重复日志 } // 更新或添加这条日志的最新输出时间 _lastLoggedEntries.AddOrUpdate(logContent, DateTime.Now, (key, oldVal) => DateTime.Now); return FilterDecision.Accept; } }
然后在你的log4net配置文件中,把这个Filter加到自定义Appender的最前面:
<appender name="YourCustomAppender" type="YourApp.Logging.YourCustomAppender"> <!-- 先加载重复日志过滤器 --> <filter type="YourApp.Logging.DuplicateLogFilter"> <blockIntervalSeconds value="30" /> <!-- 可根据需求调整间隔,比如30秒内同内容只打一次 --> </filter> <!-- 你的Appender原有配置 --> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /> </layout> </appender>
2. 针对特定故障日志做精准限流
如果重复日志是固定场景(比如Token服务报错的特定消息),可以先筛选出这类日志,再单独限流,避免误拦截其他正常日志。
配置示例:
结合log4net自带的字符串匹配Filter,先抓出特定关键词的日志,再应用重复过滤:
<appender name="YourCustomAppender" type="YourApp.Logging.YourCustomAppender"> <!-- 第一步:匹配包含Token服务故障的日志 --> <filter type="log4net.Filter.StringMatchFilter"> <stringToMatch value="Token服务故障" /> <!-- 替换成你实际的错误关键词 --> <acceptOnMatch value="true" /> </filter> <!-- 第二步:对这类日志做重复拦截 --> <filter type="YourApp.Logging.DuplicateLogFilter"> <blockIntervalSeconds value="60" /> <!-- 每分钟只输出一次 --> </filter> <!-- 第三步:拒绝其他未匹配到的日志(仅针对这类场景生效) --> <filter type="log4net.Filter.DenyAllFilter" /> <!-- 原有布局配置 --> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /> </layout> </appender>
3. 开启日志缓冲降低瞬时输出量
如果是瞬时爆发的重复日志,还可以给Appender加缓冲配置,让log4net攒够一定数量或到时间再批量输出,减少短时间内的日志条数:
<appender name="YourCustomAppender" type="YourApp.Logging.YourCustomAppender"> <!-- 累计100条再提交,或者每30秒强制刷新一次 --> <bufferSize value="100" /> <flushInterval value="30000" /> <!-- 其他配置 --> </appender>
这个方案不能完全消除重复日志,但能有效降低触发配额超限的概率。
几个小提醒
- 自定义Filter一定要保证线程安全,毕竟微服务是多线程环境,用
ConcurrentDictionary就没问题。 - 可以根据实际情况调整拦截间隔,比如故障期间希望保留一定的日志时效性,就把间隔设短一点;想彻底压量就设长一点。
- Filter的顺序很重要,要先做过滤逻辑,再进入Appender的业务处理流程。
内容的提问来源于stack exchange,提问作者Juan E
相关产品推荐
相关产品推荐

