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

Log4j2自定义LocalLogger类异常:仅输出FATAL日志问题排查

Log4j2编程式配置日志级别失效问题排查与解决

问题描述

需求如下:

  • TRACE至INFO级日志输出到infoLog.log
  • WARN至FATAL级日志输出到errorLog.log
  • 所有日志同时输出到控制台

采用编程式配置动态设置日志路径,但当前仅能在控制台及日志文件中看到FATAL级日志,其他级别日志无输出。

核心问题点

1. 日志路径判断逻辑完全反转

原代码中三目运算符的条件逻辑错误:

String infoLog = config != null && config.getLogFile() != null && config.getLogFile().isEmpty() ? config.getLogFile() : "infoLog.log";

这里的config.getLogFile().isEmpty()表示当配置路径为空时才使用配置值,完全不符合预期。正确逻辑应该是当配置路径不为空时才使用配置值,需要改为!config.getLogFile().isEmpty()。

2. ThresholdFilter无法满足级别范围需求

原代码使用ThresholdFilter过滤日志级别,该过滤器仅能控制">=指定级别"的日志通过,无法限定级别范围:

  • InfoFile的过滤器设置为Level.INFO,会导致WARN及以上级别日志也写入infoLog.log,违反需求
  • InfoFile需要限定TRACE到INFO的范围,应使用LevelRangeFilter

3. 根日志级别初始化存在潜在风险

原代码中Level.getLevel(logLevel)如果传入无效级别字符串会返回null,此时根日志会默认使用Level.ERROR,导致低级别日志被过滤。

修正后的完整代码

修正后的configureLogger方法

private void configureLogger() {
    // 修正路径判断逻辑:配置路径不为空时使用配置值,否则用默认值
    String infoLog = "infoLog.log";
    String errorLog = "errorLog.log";
    org.apache.logging.log4j.Level rootLevel = org.apache.logging.log4j.Level.TRACE;

    if (config != null) {
        if (config.getLogFile() != null && !config.getLogFile().isEmpty()) {
            infoLog = config.getLogFile();
        }
        if (config.getErrorLogFile() != null && !config.getErrorLogFile().isEmpty()) {
            errorLog = config.getErrorLogFile();
        }
        if (config.getLogLevel() != null && !config.getLogLevel().isEmpty()) {
            org.apache.logging.log4j.Level parsedLevel = org.apache.logging.log4j.Level.getLevel(config.getLogLevel());
            if (parsedLevel != null) {
                rootLevel = parsedLevel;
            }
        }
    }

    try (LoggerContext context = (LoggerContext) LogManager.getContext(true)) {
        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

        builder.setStatusLevel(org.apache.logging.log4j.Level.WARN);
        builder.setConfigurationName("DynamicConfig");

        // 控制台Appender
        AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
        consoleAppender.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
        builder.add(consoleAppender);

        // Info文件Appender:限定TRACE到INFO级别
        AppenderComponentBuilder fileInfoAppender = builder.newAppender("InfoFile", "FILE")
                .addAttribute("fileName", infoLog)
                .addAttribute("append", "true");
        fileInfoAppender.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
        // 使用LevelRangeFilter限定级别范围
        fileInfoAppender.add(builder.newFilter("LevelRangeFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
                .addAttribute("minLevel", org.apache.logging.log4j.Level.TRACE)
                .addAttribute("maxLevel", org.apache.logging.log4j.Level.INFO));
        builder.add(fileInfoAppender);

        // Error文件Appender:限定WARN到FATAL级别
        AppenderComponentBuilder fileErrorAppender = builder.newAppender("ErrorFile", "FILE")
                .addAttribute("fileName", errorLog)
                .addAttribute("append", "true");
        fileErrorAppender.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level: %msg%n"));
        fileErrorAppender.add(builder.newFilter("LevelRangeFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
                .addAttribute("minLevel", org.apache.logging.log4j.Level.WARN)
                .addAttribute("maxLevel", org.apache.logging.log4j.Level.FATAL));
        builder.add(fileErrorAppender);

        // 根Logger设置:使用修正后的级别,关联所有Appender
        RootLoggerComponentBuilder rootLogger = builder.newRootLogger(rootLevel);
        rootLogger.add(builder.newAppenderRef("Console"));
        rootLogger.add(builder.newAppenderRef("InfoFile"));
        rootLogger.add(builder.newAppenderRef("ErrorFile"));
        builder.add(rootLogger);

        org.apache.logging.log4j.core.config.Configuration configuration = builder.build();
        context.start(configuration);
    }
}

测试验证

运行测试类:

public class TestingMain {
    public static void main(String[] args) {
        LocalLogger logger = new LocalLogger(TestingMain.class);
        logger.logFinest("Trace message");
        logger.logFine("Debug message");
        logger.logInfo("Test info message");
        logger.logWarning("Test warn message");
        logger.logSevere("Test", "123", new Exception());
    }
}

预期效果:

  • 控制台输出所有级别日志
  • infoLog.log中包含TRACE、DEBUG、INFO级日志
  • errorLog.log中包含WARN、FATAL级日志

内容的提问来源于stack exchange,提问作者Julian Schaefers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:34:56