配置Log4j实现ERROR日志单独存储及全级别日志多端输出问题
Log4j配置问题:com.foo包ERROR日志仅写入文件,全级别日志输出到控制台和文件
需求
- com.foo及其子包的所有ERROR级别日志写入
logs/main.log文件; - 所有级别(DEBUG、TRACE、INFO、WARN、ERROR)日志同时输出到标准输出(stdout)和文件追加器。
问题现状
尝试了两种Log4j 1.x配置方案,但logs/main.log始终包含所有级别日志,而非仅ERROR级别。
第一次尝试的配置
#Define root logger options log4j.rootLogger=TRACE, file, stdout #Define stdout appender log4j.appender.stdout=org.apache.log4j.ConsoleAppender logrj.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-5p %c{1} - %m%n #Define rolling file appender log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=logs/main.log log4j.appender.file.Append=true log4j.appender.file.ImmediateFlush=true log4j.appender.file.MaxFileSize=10MB log4j.appender.file.MaxBackupIndex=5 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d %d{Z} [%t] %-5p (%F:%L) - %m%n log4j.appender.error-log.filter.b=org.apache.log4j.varia.LevelMatchFilter log4j.appender.error-log.filter.LevelToMatch = ERROR log4j.appender.error-log.filter.AcceptOnMatch = true log4j.appender.error-log.Threshold = ERROR #Define loggers log4j.logger.com.foo.log4j=TRACE, file, stdout
第二次尝试的配置
#Define root logger options log4j.rootLogger=TRACE, file, stdout #Define stdout appender log4j.appender.stdout=org.apache.log4j.ConsoleAppender logrj.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-5p %c{1} - %m%n #Define rolling file appender log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=logs/main.log log4j.appender.file.Append=true log4j.appender.file.ImmediateFlush=true log4j.appender.file.MaxFileSize=10MB log4j.appender.file.MaxBackupIndex=5 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d %d{Z} [%t] %-5p (%F:%L) - %m%n log4j.appender.error-log.filter.b=org.apache.log4j.varia.LevelRangeFilter log4j.appender.error-log.filter.LevelMin = ERROR log4j.appender.error-log.filter.LevelMax = ERROR log4j.appender.error-log.filter.AcceptOnMatch = true log4j.appender.error-log.Threshold = ERROR #Define loggers log4j.logger.com.foo.log4j=TRACE, file, stdout
构建依赖(Gradle)
plugins { // Apply the scala plugin to add support for Scala id 'scala' // Apply the java-library plugin for API and implementation separation. id 'java-library' } repositories { // Use jcenter for resolving dependencies. // You can declare any Maven/Ivy/file repository here. jcenter() } dependencies { // Use Scala 2.13 in our library project implementation 'org.scala-lang:scala-library:2.13.2' implementation 'org.apache.logging.log4j:log4j-api:2.17.0' implementation 'org.apache.logging.log4j:log4j-core:2.17.0' // Use Scalatest for testing our library testImplementation 'junit:junit:null' testImplementation 'org.scalatest:scalatest_2.13:3.1.2' testImplementation 'org.scalatestplus:junit-4-12_2.13:3.1.2.0' implementation 'log4j:log4j:1.2.17' // Need scala-xml at test runtime testRuntimeOnly 'org.scala-lang.modules:scala-xml_2.13:1.2.0' }
应用代码
com.foo.Application
package com.foo import com.foo.server.Server import com.foo.ui.UI object Application extends App { val server = Server() val ui = new UI(server) ui.message("hello") }
com.foo.ui.UI
package com.foo.ui import com.foo.server.Server import org.apache.log4j.LogManager class UI(server: Server) { val log = LogManager.getLogger(this.getClass) def message(string: String): Unit = { log.trace("ui got message " + string) server.message(string) } }
com.foo.server.Server
package com.foo.server import org.apache.log4j.LogManager case class Server() { val log = LogManager.getLogger(this.getClass) def message(string: String): Unit = { log.info("server got message "+ "message") log.error("server raised error on message "+ "message") } }
问题分析
- 过滤器绑定错误:两次尝试中,过滤器都配置在不存在的
error-logAppender上,实际文件Appender是file,过滤器未生效; - Logger路径错误:配置的
log4j.logger.com.foo.log4j是错误包路径,应为com.foo; - 依赖冲突:同时引入Log4j 1.x和2.x依赖,导致日志系统行为异常;
- 拼写错误:控制台Appender的Target配置写成
logrj.appender.stdout.Target,正确应为log4j.appender.stdout.Target。
正确配置方案
方案1:升级到Log4j 2.x(推荐)
步骤1:清理依赖
移除Log4j 1.x依赖,添加Log4j 1.x API桥接包以兼容现有代码:
dependencies { implementation 'org.scala-lang:scala-library:2.13.2' // 使用Log4j 2.x核心包 implementation 'org.apache.logging.log4j:log4j-api:2.17.0' implementation 'org.apache.logging.log4j:log4j-core:2.17.0' // 桥接Log4j 1.x API implementation 'org.apache.logging.log4j:log4j-1.2-api:2.17.0' testImplementation 'org.scalatest:scalatest_2.13:3.1.2' testImplementation 'org.scalatestplus:junit-4-12_2.13:3.1.2.0' testRuntimeOnly 'org.scala-lang.modules:scala-xml_2.13:1.2.0' }
步骤2:Log4j 2.x配置文件(log4j2.xml 放在src/main/resources下)
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <!-- 控制台Appender:输出所有级别日志 --> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%-5p %c{1} - %m%n"/> </Console> <!-- 文件Appender:仅输出ERROR级别日志 --> <RollingFile name="File" fileName="logs/main.log" filePattern="logs/main-%d{yyyy-MM-dd}-%i.log"> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d %d{Z} [%t] %-5p (%F:%L) - %m%n"/> <Policies> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <DefaultRolloverStrategy max="5"/> </RollingFile> </Appenders> <Loggers> <!-- com.foo包及其子包:输出所有级别到控制台,仅ERROR到文件 --> <Logger name="com.foo" level="TRACE" additivity="false"> <AppenderRef ref="Console"/> <AppenderRef ref="File" level="ERROR"/> </Logger> <!-- Root Logger:默认输出到控制台 --> <Root level="TRACE"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
方案2:修正Log4j 1.x配置
# Root Logger:输出所有级别到控制台 log4j.rootLogger=TRACE, stdout # 控制台Appender log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-5p %c{1} - %m%n # 文件Appender:仅保留ERROR级别 log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=logs/main.log log4j.appender.file.Append=true log4j.appender.file.ImmediateFlush=true log4j.appender.file.MaxFileSize=10MB log4j.appender.file.MaxBackupIndex=5 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d %d{Z} [%t] %-5p (%F:%L) - %m%n # 添加LevelMatchFilter,仅接受ERROR log4j.appender.file.filter.1=org.apache.log4j.varia.LevelMatchFilter log4j.appender.file.filter.1.LevelToMatch=ERROR log4j.appender.file.filter.1.AcceptOnMatch=true # 添加DenyAllFilter,拒绝其他所有日志 log4j.appender.file.filter.2=org.apache.log4j.varia.DenyAllFilter # com.foo包Logger:输出所有级别到控制台,同时将ERROR输出到文件 log4j.logger.com.foo=TRACE, file # 关闭additivity,避免重复输出到root的Appender log4j.additivity.com.foo=false
验证结果
运行应用后:
- 控制台会输出
TRACE、INFO、ERROR等所有级别的日志; logs/main.log中仅会出现ERROR级别的日志。
内容的提问来源于stack exchange,提问作者Chris Bedford
相关产品推荐
相关产品推荐

