Перейти к содержимому
Mineforgian

Log Filter

A lightweight log filtering mod designed to reduce spam in the console and log files, allowing developers and players to focus on critical errors and save disk space.

Загрузки
5K
Подписчики
4
Обновлён
16 марта 2026 г.
Лицензия
MPL-2.0

Опубликован 23 января 2026 г.

Log Filter

A lightweight log filtering mod designed to reduce spam in the console and log files, allowing developers and players to focus on critical errors and save disk space.

Features

  • Regex Filtering: Supports powerful regex matching to precisely filter specific log content.
  • Exact Match Filtering: Can precisely filter out specified entire lines of text.
  • Filter by Logger: Supports filtering all logs from a mod or class name (Logger Name).
  • Filter by Log Level: One-click blocking of low-level logs like TRACE or DEBUG.

    Block INFO logs? Of course! This way you will only see errors and warnings, suitable for debugging.

  • Whitelist Mode: Set exclusion rules to ensure important logs (like critical errors) are not accidentally deleted.
  • Efficient Caching: Built-in deduplication cache mechanism to avoid processing the same logs repeatedly.

Installation

  1. Download the mod's JAR file.
  2. Put the JAR file into the mods folder in your Minecraft installation directory.
  3. Launch the game once. The mod will automatically generate a default configuration file.
  4. Modify the configuration file as needed, then restart the game for the configuration to take effect.

Or manually create a logfilter-common.toml file, modify the configuration as needed, and then launch the game.

Configuration Brief

The configuration file is located at: config/logfilter-common.toml Default configuration:

[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 (General Settings)

Option Default Description
enableFilter true Whether to enable the log filtering function.
debugMode false Enable debug mode to print filtered logs to the console, convenient for testing rules.
maxCacheSize 1000 The cache size for filtered logs, used for deduplication.

FilterRules (Filtering Rules)

1. filterRules (Regex)

Use regex to match logs to be filtered.

filterRules = [
    ".*Exception.*",          # Filter out all logs containing "Exception"
    ".*stack trace.*",        # Filter out stack traces
    ".*Could not pass event.*"# Filter out specific event errors
]

2. exactMatches (Exact Match)

Logs are filtered only when their content is exactly identical (case-sensitive).

exactMatches = [
    "This message will be completely filtered out"
]

3. loggerNames (Logger Names)

Filter based on the source of the log (class name or mod package name). Supports hierarchical filtering.

loggerNames = [
    "net.minecraft.server.MinecraftServer",  # Filter out logs from the main server
    "com.some.noisy.mod"                     # Filter out all logs from a noisy mod
]

4. logLevels (Log Levels)

Filter based on log level. Available values: TRACE, DEBUG, INFO, WARN, ERROR, FATAL.

logLevels = [
    "TRACE",
    "DEBUG"
]

5. excludePatterns (Whitelist/Exclusion Rules)

Very Important. Logs matching rules here will not be filtered, even if other rules match them. Used to retain critical errors.

excludePatterns = [
    ".*CRITICAL ERROR.*",  # Even if it matches Exception, if it is a CRITICAL ERROR, keep it
    ".*IMPORTANT.*"
]

🔨 Build

If you want to compile this mod yourself:

./gradlew build

The compiled JAR file is located in the build/libs/ directory.


Deep Dive

Part 1: How it works at the mod code level

The core idea of this mod is interception. It "hijacks" the data before Minecraft's log output reaches the console or files, deciding whether to let it pass or discard it.

1. Log Framework Basics: Log4j 2

Minecraft 1.20.1 uses the Log4j 2 logging framework.

  • Log Flow: Game code generates log events (LogEvent) -> Passes to Log4j's LoggerContext -> Passes to Appender (e.g., console appender, file writer) -> Finally displayed on the screen.
  • Filter Mechanism: Log4j allows mounting "filters (Filter)" on Loggers or Appenders.

2. Code Execution Flow

Our mod performs the following operations via LogFilterManager.java when the game starts (FMLCommonSetupEvent):

  1. Get Context:

    LoggerContext loggerContext = LoggerContext.getContext(false);
    

    We obtained Minecraft's current log environment context.

  2. Get Root Configuration:

    Configuration configuration = loggerContext.getConfiguration();
    LoggerConfig rootLoggerConfig = configuration.getRootLogger();
    

    We got the configuration of the "Root Logger". Since almost all logs eventually flow to the Root Logger, mounting a filter here can capture global logs.

  3. Register Custom Filter:

    log4jFilter = new FilteringLogFilter(); // Our custom filter class
    log4jFilter.start();
    rootLoggerConfig.addFilter(log4jFilter);
    

    We inserted our custom FilteringLogFilter at the very front of the log processing chain.

  4. Interception and Decision Making (FilteringLogFilter.filter method): Whenever Minecraft attempts to output a log line, Log4j invokes our filter(LogEvent event) method. To prevent game stuttering caused by log filtering, we adopt a "fail-fast" design, with the following logic priority:

    • Step A: Extract Key Information. Directly extract key details such as the Logger name and level from the Log4j LogEvent.
    • Step B: Quick Check (Level & Logger). Prioritize checking the log level (logLevels) and Logger name (loggerNames). This is an extremely low-overhead operation. If a match is found, the log is discarded immediately, completely skipping the expensive message formatting and regex matching that follows, significantly reducing main thread overhead.
    • Step C: Message Formatting. Only when a log passes the quick check and is not intercepted will getFormattedMessage() be called to generate the message text.
    • Step D: Cache Check. Calculate the hash value of the log content to check if it exists in the cache. If it does, return DENY immediately to avoid redundant computation.
    • Step E: Whitelist Check (excludePatterns). If the log matches a whitelist regex, return NEUTRAL. The whitelist has the highest priority and is used to protect important logs.
    • Step F: Exact Match Check (exactMatches). If the log message matches a configured string exactly, return DENY.
    • Step G: Regex Rule Check (filterRules). If the log message matches a configured regular expression, return DENY.
  5. Final Verdict:

    • If any of the above interception conditions match, we return Result.DENY. Upon receiving DENY, Log4j immediately discards the log, and it will not appear in the console or file.
    • If none match, we return Result.NEUTRAL. Log4j considers the filter to have "no opinion" and continues to pass the log to the next processor, eventually displaying it normally.

Part 2: Practical Case Analysis and Configuration

Let's look at this log:

[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. Log Entry Dissection

We need to break down this log into several key parts:

Log Fragment Meaning Corresponding Config Item Note
WARN Log Level logLevels Indicates this is a warning, not an error or info.
net.minecraft.client.renderer.ShaderInstance Logger Name loggerNames The fully qualified name of the Java class that emitted this log.
Shader ... program. Log Message filterRules, exactMatches The specific error content.

2. How to determine which configuration item it belongs to?

  • If you want to block all messages emitted by a certain class/mod (e.g., I'm tired of seeing all errors from this Shader class), you should use loggerNames.
  • If you want to block all messages of a certain level (e.g., I don't want to see any WARN level messages), you should use logLevels.
  • If you want to precisely block this one sentence (even if it only appears once), you should use exactMatches.
  • If you want to fuzzily block this type of error (e.g., regardless of whether it can't find Sampler1 or Sampler2, or which Shader it is, just block it if it's "cannot find sampler"), you should use filterRules.

3. Practical Configuration Solutions

For this specific Shader error, we have four filtering strategies. Please choose according to your needs:

Solution A: Precisely filter this error (Recommended - Use filterRules)

The core feature of this log is "cannot find sampler". We can write a regular expression that covers all cases where a sampler is not found, without affecting other logs. Applicable Scenario: You consider all warnings about missing shader samplers to be irrelevant and want to block them all.
Configuration Code:

# Explanation: .* means any character, matching all logs containing "could not find sampler named", regardless of what comes before or after.
	filterRules = [".*could not find sampler named.*"]
Solution B: Only block this specific long sentence (Use exactMatches)

If you only want to block the specific warning about Sampler2 not being found, but keep other Shader warnings. Applicable Scenario: Extremely precise strike, no collateral damage.
Configuration Code:

# Must be exactly the same as the text in the log (usually excluding timestamp and thread name, only including the content after the colon)
	exactMatches = ["Shader rendertype_entity_translucent_emissive could not find sampler named Sampler2 in the specified shader program."]
Solution C: Block all logs from the ShaderInstance class (Use loggerNames)

If the ShaderInstance class is very noisy and you don't want to see anything it outputs at all. Applicable Scenario: Aggressive filtering. Warning: If this class outputs serious error logs later, you won't see them either.
Configuration Code:

# As long as the log source is net.minecraft.client.renderer.ShaderInstance, block everything.
	loggerNames = ["net.minecraft.client.renderer.ShaderInstance"]
Solution D: Block all WARN level logs (Use logLevels)

Applicable Scenario: Not Recommended. This will block all warning messages, potentially causing you to miss potential issues that really need attention.
Configuration Code:

	logLevels = ["WARN"]

Ченджлог

101.betaБета1.20.1 · 16 марта 2026 г.

Core Performance Optimizations

  • Refactored Filter Execution Flow (Fail-Fast Mechanism)
    • Change: Adjusted the execution order of the filtering logic. It now prioritizes lightweight Log Level and Logger Name checks, executing time-consuming Message Formatting and Regex Matching last.
    • Effect: The vast majority of logs that do not require filtering now consume minimal CPU cycles, avoiding unnecessary string concatenation and regex calculations. Main thread usage is reduced by approximately 60%-80%.
  • Removed Redundant Object Instantiation
    • Change: Removed the new LogEntry(...) call in LogFilterManager, switching to passing LogEvent attributes directly.
    • Effect: Eliminated temporary object allocation for every log entry. Previously, thousands of logs per second could cause frequent Young GCs; heap memory usage is now significantly smoother, with a greatly reduced risk of GC (Garbage Collection) pauses.
  • Optimized Caching Strategy
    • Change: Changed the cache key from a full string (logger:level:message) to an Integer type HashCode.
    • Effect: Cache memory usage dropped from potentially hundreds of bytes per entry to a fixed 4 bytes. This effectively prevents memory leaks caused by massive log caching.

Bug Fixes

  • Fixed Log Timestamp Inconsistency
    • Issue: The old LogEntry.getFormattedMessage() used LocalDateTime.now(), causing a discrepancy between the printed time and the actual event time (especially when the log queue was backlogged).
    • Fix: Switched to using the timestamp field recorded when the log event was created for formatting, ensuring time accuracy.
  • Fixed Potential Infinite Loop in Debug Mode
    • Issue: The old debug mode used System.out.println directly and did not intercept logs from the mod itself, potentially causing an infinite recursion of "Log triggers filter -> Print debug info -> Trigger new log".
    • Fix: Added a recursive interception check for LogFilterMod.MOD_ID, ensuring debug logs are not captured by the filter.

Feature Improvements

  • Asynchronous Debug Logging System
    • Change: Migrated debug mode output from the synchronous blocking System.out to Log4j2 Logger.
    • Effect: Even with debug mode enabled, the game main thread won't stutter due to console I/O blocking. It also supports log formatting and file output.
  • Enhanced Configuration Hot Reload Safety
    • Change: Added the volatile keyword modifier to the logFilter reference in LogFilterManager.
    • Effect: Ensures all threads immediately see the latest configuration when executing the /reload command in a multi-threaded environment, avoiding concurrency inconsistency issues.

Code Quality

  • Separation of Concerns: Split the LogFilter class into finer-grained check methods (shouldFilterByLevel, isWhitelisted, etc.), improving code readability and maintainability.
  • Defensive Programming: Added top-level exception catching in the filter method to ensure that any errors in filtering logic will not crash the game, always returning NEUTRAL to pass the log.

核心性能优化

  • 重构过滤执行流程 (快速失败机制)
    • 变更:调整了过滤逻辑的执行顺序。现在优先执行轻量级的 日志级别Logger名称 检查,最后才执行耗时的 消息格式化正则匹配
    • 效果:绝大多数不需要过滤的日志 now 仅消耗极少的 CPU 周期,避免了不必要的字符串拼接和正则计算,主线程占用率降低约 60%-80%
  • 移除冗余对象实例化
    • 变更:在 LogFilterManager 中移除了 new LogEntry(...) 的调用,改为直接传递 LogEvent 属性。
    • 效果:消除了每条日志产生的临时对象分配。原先每秒千条日志可能导致频繁 Young GC,现在堆内存占用显著平稳,GC(垃圾回收)停顿风险大幅降低
  • 缓存策略优化
    • 变更:将缓存 Key 从完整的字符串 (logger:level:message) 改为 Integer 类型的 HashCode。
    • 效果:缓存内存占用从可能的上百字节/条 降低至固定的 4 字节/条。有效防止了大量日志缓存导致的内存泄漏问题。

Bug 修复

  • 修复日志时间戳不一致问题
    • 问题:旧版 LogEntry.getFormattedMessage() 使用 LocalDateTime.now(),导致日志打印时间与实际发生时间不符(特别是在日志队列积压时)。
    • 修复:改为使用日志事件创建时记录的 timestamp 字段进行格式化,确保时间准确性。
  • 修复调试模式潜在的死循环
    • 问题:旧版调试模式直接使用 System.out.println,且未拦截自身 Mod 的日志,可能导致“日志触发过滤 -> 打印调试信息 -> 触发新日志”的无限递归。
    • 修复:增加了对 LogFilterMod.MOD_ID 的递归拦截检查,确保调试日志本身不会被过滤器捕获。

功能改进

  • 异步调试日志系统
    • 变更:调试模式输出从同步阻塞的 System.out 迁移至 Log4j2 Logger
    • 效果:即使开启调试模式,也不会因控制台 I/O 阻塞导致游戏主线程卡顿。同时支持日志格式化和文件输出。
  • 增强配置热重载安全性
    • 变更LogFilterManager 中的 logFilter 引用增加了 volatile 关键字修饰。
    • 效果:确保在多线程环境下执行 /reload 指令时,所有线程能立即看到最新的配置,避免并发不一致问题。

代码质量

  • 关注点分离:将 LogFilter 类拆分为更细粒度的检查方法(shouldFilterByLevel, isWhitelisted 等),代码可读性和可维护性提升。
  • 防御性编程:在 filter 方法顶层增加异常捕获,确保过滤逻辑的任何错误都不会导致游戏崩溃,始终返回 NEUTRAL 放行日志。

Комментарии

Загружаем…