通过编程配置Log4J时日志文件为空的原因及解决方法
Log4J编程配置:日志文件创建但为空的问题排查与解决
问题场景
在Zorin 17.1 Core系统搭配OpenJDK 22环境下,通过编程方式配置Log4J,期望日志同时输出到控制台和日志文件,但控制台输出正常,日志文件虽已创建却始终为空。
最小可运行示例代码
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; public class Main { public static void main(String[] args) { Level level = Level.WARN; ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder(); builder.setStatusLevel(level); builder.setConfigurationName("BuilderTest"); AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE") .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT) .add(builder.newLayout("PatternLayout") .addAttribute("pattern", "xxxxx %d [%t] %-5level: %msg%n%throwable")) .add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL) .addAttribute("marker", "FLOW")); builder.add(appenderBuilder); appenderBuilder = builder.newAppender("File", "File") .addAttribute("fileName", "logs/main.log") .addAttribute("append", true) .addAttribute("locking", false) .addAttribute("immediateFlush", true) .add(builder.newLayout("PatternLayout") .addAttribute("pattern", "xxxxxx %d [%t] %-5level: %msg%n%throwable")); builder.add(appenderBuilder); builder .add(builder.newLogger("org.apache.logging.log4j", level) .add(builder.newAppenderRef("Stdout")) .addAttribute("additivity", false)); builder.add( builder .newRootLogger(level) .add(builder.newAppenderRef("Stdout")) ); Configurator.reconfigure(builder.build()); LoggerConfig loggerConfig = new LoggerConfig(Main.class.getPackageName(), level, false); Configurator.setLevel(Main.class.getPackageName(), level); LogManager.getRootLogger().error("setLoggingLevel(): Logging level set to %s.".formatted(level)); } }
控制台输出
xxxxx 2024-08-30 01:43:22,830 [main] ERROR: setLoggingLevel(): Logging level set to WARN.
原pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.log4j-test</groupId> <artifactId>log4j-test</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>22</maven.compiler.source> <maven.compiler.target>22</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.3.4</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>3.0.0-beta2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>3.0.0-beta2</version> </dependency> </dependencies> </project>
问题原因
- File Appender未关联到日志记录器:代码中仅为Root Logger添加了控制台Appender的引用,没有将创建好的File Appender关联到Root Logger或自定义Logger,导致日志不会写入文件。
- 依赖版本冲突:pom.xml中同时引入了Log4J 1.2.x和Log4J 2.x(3.0.0-beta2)两个不兼容的版本,会引发类加载混乱,可能导致部分配置逻辑失效。
- 自定义Logger配置无效:代码中创建了
LoggerConfig实例但未将其添加到Log4J的配置中,仅调用Configurator.setLevel无法让自定义Logger生效,也不会关联File Appender。
解决方案
1. 清理冲突依赖
移除Log4J 1.2.17和commons-logging依赖(若项目无需兼容旧代码),仅保留Log4J 2.x的api和core依赖,避免版本冲突。
2. 关联File Appender到Root Logger
在构建Root Logger时,添加File Appender的引用,确保日志会同时输出到控制台和文件。
3. (可选)正确配置自定义Logger
如果需要针对特定包配置日志,应通过ConfigurationBuilder添加自定义Logger,并关联所需的Appender,而非单独创建LoggerConfig实例。
修正后的代码
修正后的Main.java
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; public class Main { public static void main(String[] args) { Level level = Level.WARN; ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder(); builder.setStatusLevel(level); builder.setConfigurationName("BuilderTest"); // 配置控制台Appender AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE") .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT) .add(builder.newLayout("PatternLayout") .addAttribute("pattern", "xxxxx %d [%t] %-5level: %msg%n%throwable")) .add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL) .addAttribute("marker", "FLOW")); builder.add(appenderBuilder); // 配置文件Appender appenderBuilder = builder.newAppender("File", "File") .addAttribute("fileName", "logs/main.log") .addAttribute("append", true) .addAttribute("locking", false) .addAttribute("immediateFlush", true) .add(builder.newLayout("PatternLayout") .addAttribute("pattern", "xxxxxx %d [%t] %-5level: %msg%n%throwable")); builder.add(appenderBuilder); // 配置org.apache.logging.log4j包的Logger builder .add(builder.newLogger("org.apache.logging.log4j", level) .add(builder.newAppenderRef("Stdout")) .addAttribute("additivity", false)); // 配置Root Logger,同时关联控制台和文件Appender builder.add( builder .newRootLogger(level) .add(builder.newAppenderRef("Stdout")) .add(builder.newAppenderRef("File")) // 新增File Appender引用 ); // 应用配置 Configurator.reconfigure(builder.build()); // 若需要针对当前包设置日志级别,直接通过Configurator设置即可 Configurator.setLevel(Main.class.getPackageName(), level); LogManager.getRootLogger().error("setLoggingLevel(): Logging level set to %s.".formatted(level)); } }
修正后的pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.log4j-test</groupId> <artifactId>log4j-test</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>22</maven.compiler.source> <maven.compiler.target>22</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 使用稳定版Log4J 2.x,beta版本可能存在未知问题 --> <log4j.version>2.23.1</log4j.version> </properties> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </project>
验证效果
运行修正后的代码,控制台会输出原有日志,同时logs/main.log文件中会写入对应的日志内容,格式与配置的PatternLayout一致。
内容的提问来源于stack exchange,提问作者Pixelcode
相关产品推荐
相关产品推荐

