
日志过滤器
一个轻量级日志过滤模组,旨在减少控制台和日志文件中的垃圾信息,让开发者和玩家能够专注于关键错误并节省磁盘空间。
日志过滤器
一个轻量级的日志过滤模组,旨在减少控制台和日志文件中刷屏的信息,让开发者和玩家专注于关键错误并节省磁盘空间。
功能特性
- 正则过滤:支持强大的正则匹配,精确过滤特定日志内容。
- 精确匹配过滤:可以精确过滤掉指定的整行文本。
- 按记录器过滤:支持过滤某个模组或类名(Logger Name)的所有日志。
- 按日志等级过滤:一键屏蔽
TRACE、DEBUG等低级日志。屏蔽
INFO日志?当然可以!这样你只会看到错误和警告,适合调试使用。 - 白名单模式:设置排除规则,确保重要日志(如关键错误)不会被误删。
- 高效缓存:内置去重缓存机制,避免重复处理相同日志。
安装
- 下载模组的 JAR 文件。
- 将 JAR 文件放入你的 Minecraft 安装目录下的
mods文件夹中。 - 启动一次游戏。模组会自动生成默认配置文件。
- 根据需要修改配置文件,然后重启游戏使配置生效。
或者手动创建
logfilter-common.toml文件,根据需要修改配置,然后启动游戏。
配置简要说明
配置文件位于:config/logfilter-common.toml
默认配置:
[General]
#Enable or disable log filtering
enableFilter = true
#Enable debug mode to see which logs are being filtered
debugMode = false
#Maximum size of filtered log cache (for duplicate detection)
#Range: 100 ~ 10000
maxCacheSize = 1000
[FilterRules]
#Regex patterns to filter log messages
filterRules = []
#Exact message strings to filter (case-sensitive)
exactMatches = []
#Logger names to completely filter (e.g., 'net.minecraft.server.MinecraftServer')
loggerNames = []
#Log levels to filter: TRACE, DEBUG, INFO, WARN, ERROR, FATAL
logLevels = ["TRACE", "DEBUG"]
#Regex patterns that will EXCLUDE logs from filtering (whitelist)
excludePatterns = []
General(常规设置)
| 选项 | 默认值 | 描述 |
|---|---|---|
enableFilter |
true |
是否启用日志过滤功能。 |
debugMode |
false |
启用调试模式,将过滤的日志打印到控制台,便于测试规则。 |
maxCacheSize |
1000 |
已过滤日志的缓存大小,用于去重。 |
FilterRules(过滤规则)
1. filterRules(正则表达式)
使用正则匹配需要过滤的日志。
filterRules = [
".*Exception.*", # 过滤掉所有包含 "Exception" 的日志
".*stack trace.*", # 过滤掉堆栈跟踪
".*Could not pass event.*"# 过滤掉特定事件错误
]
2. exactMatches(精确匹配)
只有当日志内容完全一致(区分大小写)时才会被过滤。
exactMatches = [
"This message will be completely filtered out"
]
3. loggerNames(记录器名称)
根据日志的来源(类名或模组包名)进行过滤。支持层级过滤。
loggerNames = [
"net.minecraft.server.MinecraftServer", # 过滤掉主服务器的日志
"com.some.noisy.mod" # 过滤掉某个刷屏模组的所有日志
]
4. logLevels(日志等级)
根据日志等级进行过滤。可用值:TRACE、DEBUG、INFO、WARN、ERROR、FATAL。
logLevels = [
"TRACE",
"DEBUG"
]
5. excludePatterns(白名单/排除规则)
非常重要。匹配此处规则的日志将不会被过滤,即使其他规则也匹配了它们。用于保留关键错误。
excludePatterns = [
".*CRITICAL ERROR.*", # 即使匹配 Exception,如果是 CRITICAL ERROR,也保留
".*IMPORTANT.*"
]
🔨 构建
如果你想自行编译此模组:
./gradlew build
编译后的 JAR 文件位于 build/libs/ 目录中。
深入解析
第一部分:模组代码层面的工作原理
此模组的核心思想是拦截。它在 Minecraft 的日志输出到达控制台或文件之前“劫持”数据,决定是放行还是丢弃。
1. 日志框架基础:Log4j 2
Minecraft 1.20.1 使用 Log4j 2 日志框架。
- 日志流程:游戏代码生成日志事件(
LogEvent)-> 传递给 Log4j 的LoggerContext-> 传递给Appender(如控制台 appender、文件写入器)-> 最终显示在屏幕上。 - 过滤器机制:Log4j 允许在 Logger 或 Appender 上挂载“过滤器(
Filter)”。
2. 代码执行流程
我们的模组在游戏启动时(FMLCommonSetupEvent)通过 LogFilterManager.java 执行以下操作:
获取上下文:
LoggerContext loggerContext = LoggerContext.getContext(false);我们获取了 Minecraft 当前的日志环境上下文。
获取根配置:
Configuration configuration = loggerContext.getConfiguration(); LoggerConfig rootLoggerConfig = configuration.getRootLogger();我们获取了“根 Logger”的配置。由于几乎所有日志最终都会流向根 Logger,因此在此处挂载过滤器可以捕获全局日志。
注册自定义过滤器:
log4jFilter = new FilteringLogFilter(); // 我们的自定义过滤器类 log4jFilter.start(); rootLoggerConfig.addFilter(log4jFilter);我们将自定义的
FilteringLogFilter插入到日志处理链的最前端。拦截与决策(
FilteringLogFilter.filter方法): 每当 Minecraft 尝试输出一行日志时,Log4j 都会调用我们的filter(LogEvent event)方法。为避免日志过滤导致游戏卡顿,我们采用“快速失败”设计,逻辑优先级如下:- 步骤 A:提取关键信息。 直接从 Log4j 的
LogEvent中提取 Logger 名称和等级等关键细节。 - 步骤 B:快速检查(等级与 Logger)。 优先检查日志等级(
logLevels)和 Logger 名称(loggerNames)。这是开销极低的操作。若匹配到,日志会被立即丢弃,完全跳过后续开销昂贵的消息格式化和正则匹配,显著降低主线程开销。 - 步骤 C:消息格式化。 只有当日志通过快速检查且未被拦截时,才会调用
getFormattedMessage()生成消息文本。 - 步骤 D:缓存检查。 计算日志内容的哈希值,检查是否存在于缓存中。若存在,立即返回
DENY,避免重复计算。 - 步骤 E:白名单检查(
excludePatterns)。 若日志匹配白名单正则,返回NEUTRAL。白名单优先级最高,用于保护重要日志。 - 步骤 F:精确匹配检查(
exactMatches)。 若日志消息与配置的字符串完全一致,返回DENY。 - 步骤 G:正则规则检查(
filterRules)。 若日志消息匹配配置的正则表达式,返回DENY。
- 步骤 A:提取关键信息。 直接从 Log4j 的
最终判定:
- 若上述任一拦截条件匹配,我们返回
Result.DENY。收到DENY后,Log4j 会立即丢弃该日志,它将不会出现在控制台或文件中。 - 若均不匹配,我们返回
Result.NEUTRAL。Log4j 认为过滤器“无意见”,继续将日志传递给下一个处理器,最终正常显示。
- 若上述任一拦截条件匹配,我们返回
第二部分:实际案例分析及配置
让我们看这条日志:
[241... 00:32:22.574] [Render thread/WARN] [net.minecraft.client.renderer.ShaderInstance/]: Shader rendertype_entity_translucent_emissive could not find sampler named Sampler2 in the specified shader program.
1. 日志条目剖析
我们需要将这条日志拆解为几个关键部分:
| 日志片段 | 含义 | 对应配置项 | 备注 |
|---|---|---|---|
WARN |
日志等级 | logLevels |
表示这是警告,而非错误或信息。 |
net.minecraft.client.renderer.ShaderInstance |
记录器名称 | loggerNames |
发出此日志的 Java 类的完全限定名。 |
Shader ... program. |
日志消息 | filterRules、exactMatches |
具体的错误内容。 |
2. 如何确定它属于哪个配置项?
- 如果你想屏蔽某个类/模组发出的所有消息(例如,我厌倦了看到这个 Shader 类的所有错误),应使用
loggerNames。 - 如果你想屏蔽某个等级的所有消息(例如,我不想看到任何 WARN 级别的消息),应使用
logLevels。 - 如果你想精确屏蔽这一句话(即使它只出现一次),应使用
exactMatches。 - 如果你想模糊屏蔽这类错误(例如,无论它找不到 Sampler1 还是 Sampler2,或者无论哪个 Shader,只要“找不到 sampler”就屏蔽),应使用
filterRules。
3. 实用配置方案
针对这个特定的 Shader 错误,我们有四种过滤策略。请根据你的需求选择:
方案 A:精确过滤此错误(推荐 - 使用 filterRules)
这条日志的核心特征是“找不到 sampler”。我们可以编写一个正则表达式,涵盖所有找不到 sampler 的情况,而不影响其他日志。
适用场景:你认为所有关于着色器 sampler 缺失的警告都无关紧要,想要全部屏蔽。
配置代码:
# 说明:.* 表示任意字符,匹配所有包含 "could not find sampler named" 的日志,无论其前后是什么内容。
filterRules = [".*could not find sampler named.*"]
方案 B:只屏蔽这条特定的长句(使用 exactMatches)
如果你只想屏蔽关于 Sampler2 未找到的特定警告,但保留其他 Shader 警告。
适用场景:极其精确的打击,无附带损伤。
配置代码:
# 必须与日志中的文本完全一致(通常不包括时间戳和线程名,只包括冒号之后的内容)
exactMatches = ["Shader rendertype_entity_translucent_emissive could not find sampler named Sampler2 in the specified shader program."]
方案 C:屏蔽 ShaderInstance 类的所有日志(使用 loggerNames)
如果 ShaderInstance 类非常吵,你完全不想看到它输出的任何内容。
适用场景:激进过滤。警告:如果此类后续输出了严重错误日志,你也将看不到。
配置代码:
# 只要日志来源是 net.minecraft.client.renderer.ShaderInstance,就全部屏蔽。
loggerNames = ["net.minecraft.client.renderer.ShaderInstance"]
方案 D:屏蔽所有 WARN 级别日志(使用 logLevels)
适用场景:不推荐。这会屏蔽所有警告消息,可能导致你错过真正需要关注的潜在问题。
配置代码:
logLevels = ["WARN"]
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。