Scala项目Log4j细粒度日志配置:屏蔽库Trace日志失败
问题描述
我在Scala项目中使用Log4j日志,库中类通过LoggerFactory.getLogger(this.getClass.getName.stripSuffix("$"))创建Logger实例。项目继承了库中的类,库默认日志级别为Trace。我需要:
- 将库的日志级别设为INFO,屏蔽Trace日志
- 保持当前项目日志级别为Trace
已配置库包library.project.main.myPackage为INFO级别,项目根包project.main为Trace级别,但仍能看到库的Trace日志。
当前配置(部分省略)
status = error appenders = console appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{${LOG_DATEFORMAT_PATTERN:-MM-dd HH:mm:ss.SSS}} %highlight{${LOG_LEVEL_PATTERN:-%5p}}{FATAL=red blink, ERROR=red, WARN=yellow bold, INFO=green, DEBUG=green bold, TRACE=blue} %style{%12.12t}{magenta} %style{%20.20replace{%c{1.}:%L}{}{}}{cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx} loggers = library-logger, project-logger logger.project-logger.name = project.main logger.project-logger.level = trace logger.library-logger.name = library.project.main.myPackage logger.library-logger.level = info rootLogger.level = error rootLogger.appenderRefs = stdout rootLogger.appenderRef.stdout.ref = STDOUT
库中类代码
package library.project.main.myPackage abstract class MyExtendableClass { protected lazy val log = com.typesafe.scalalogging.Logger(LoggerFactory.getLogger( this.getClass.getName.stripSuffix("$") )) def func = { log.trace("This is a trace log from the library") } }
项目实现代码
package project.main.package import library.project.main.myPackage.MyExtendableClass class MyClazz extends MyExtendableClass { def myInitFunc = { func log.info("This is an info log after calling func") // 其他操作 } }
期望与实际输出
- 期望输出:
10-10 12:12:20.121 INFO ispatcher-27 main.package.MyClazz:30 This is an info log after calling func
- 实际输出:
10-10 10:10:10.121 TRACE ispatcher-27 myPackage.MyExtendableClass:10 This is a trace log from the library 10-10 12:12:20.121 INFO ispatcher-27 main.package.MyClazz:30 This is an info log after calling func
问题原因
库中创建Logger时使用this.getClass.getName,当子类MyClazz实例化后,this.getClass指向的是子类而非库中的父类,因此Logger的实际名称是project.main.package.MyClazz,属于项目包project.main(已设为Trace级别),所以库中的log.trace会被正常打印,之前针对库包的配置并未生效。
解决方案
方案1:修改库中的Logger创建逻辑(推荐)
将库中Logger的创建方式改为固定使用父类的类名,而非运行时子类的类名:
package library.project.main.myPackage abstract class MyExtendableClass { protected lazy val log = com.typesafe.scalalogging.Logger(LoggerFactory.getLogger( classOf[MyExtendableClass].getName.stripSuffix("$") )) def func = { log.trace("This is a trace log from the library") } }
修改后,Logger的名称为library.project.main.myPackage.MyExtendableClass,对应配置中库包的INFO级别设置,即可屏蔽Trace日志。
方案2:无法修改库代码时,通过Appender过滤器实现
在Console Appender中添加级别+类名的组合过滤器,仅拒绝来自MyExtendableClass的Trace日志:
status = error appenders = console appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{${LOG_DATEFORMAT_PATTERN:-MM-dd HH:mm:ss.SSS}} %highlight{${LOG_LEVEL_PATTERN:-%5p}}{FATAL=red blink, ERROR=red, WARN=yellow bold, INFO=green, DEBUG=green bold, TRACE=blue} %style{%12.12t}{magenta} %style{%20.20replace{%c{1.}:%L}{}{}}{cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx} # 添加过滤器:先匹配TRACE级别,再匹配类名 appender.console.filter.1.type = LevelFilter appender.console.filter.1.level = TRACE appender.console.filter.1.onMatch = NEUTRAL appender.console.filter.1.onMismatch = ACCEPT appender.console.filter.2.type = RegexFilter appender.console.filter.2.regex = ".*MyExtendableClass:[0-9]+.*" appender.console.filter.2.onMatch = DENY appender.console.filter.2.onMismatch = ACCEPT loggers = project-logger logger.project-logger.name = project.main logger.project-logger.level = trace rootLogger.level = error rootLogger.appenderRefs = stdout rootLogger.appenderRef.stdout.ref = STDOUT
该配置会先放行非TRACE级别的所有日志,对于TRACE日志,再检查是否来自MyExtendableClass,若是则拒绝输出,从而实现需求。
内容的提问来源于stack exchange,提问作者N0rb0

