动态修改springboot日志级别

线上运行时修改springboot日志级别方案

 

一、背景

为了减少日志频繁打印带来的性能影响,线上设置的日志级别相对较高。当线上应用出现问题需要我们排查的时候,可能需要适当降低日志级别(例如DEBUG)来打印更多的日志信息帮助定位问题。

传统的修改日志方式需要1、配置里修改日志级别 2、重启应用 3、问题复现排查问题。这个过程需要重启应用,比较麻烦,效率较低。考虑某一种方式能不重启应用的情况下能够动态修改日志级别。

 

二、实行方案

spring actuator支持对日志级别的运行中动态修改。

1、暴露actuator日志接口

actuator 默认暴露的http接口只有info和health,需要把loggers端点配置上才能通过调用http接口使用日志查询和配置功能。

动态修改springboot日志级别_第1张图片

 

2、集成log4j2框架

在build.gradle文件中

  1. 排除已经集成的log4j日志框架,否则会和log4j2日志框架有冲突

all*.exclude group: 'org.slf4j', module: 'slf4j-log4j12'

all*.exclude group: 'log4j', module: 'log4j'

  1. 集成log4j2日志框架

compile 'org.springframework.boot:spring-boot-starter-log4j2'

 

3、log4j2.properties配置文件模板

和原来的log4j.properties文件相似的结构。不一样的地方是需要在控制台打印里指定

appender.console.filter.threshold.level日志级别,否则默认是error级别。这样即使指定了rootLogger.level比error级别低(例如info),也无法打印info级别的日志。

级别嵌套关系:rootLogger是第一层,appender.console.filter.threshold.level是第二层。打印的日志级别是这两层同时满足的日志级别。

建议appender.console.filter.threshold.level设置成所能接受的最低级别例如debug, 然后只让rootLogger控制日志级别(info, warn,error…),因为Spring Actuator只能支持到第一层的标签例如rootLogger和logger。

 

log4j2.properties模板

​​​​​

name = PropertiesConfig  
# 定义常量  
property.filename = /XX/XX/audit.log  
# 控制台打印  
appender.console.type = Console  
appender.console.name = STDOUT  
appender.console.layout.type = PatternLayout  
appender.console.layout.pattern = %d{yyyy-MM-dd'T'HH:mm:ss'Z'} [%t] %-5p [%c] - %m%n  
appender.console.filter.threshold.type = ThresholdFilter  
appender.console.filter.threshold.level = debug  
# root引入控制台打印  
rootLogger.level = info  
rootLogger.appenderRef.stdout.ref = STDOUT  

# 审计文件打印  
appender.rolling.type = RollingFile  
appender.rolling.name = AuditFile  
appender.rolling.fileName = ${filename}  
appender.rolling.filePattern = ${filename}.%d{yyyy-MM-dd}  
appender.rolling.layout.type = PatternLayout  
appender.rolling.layout.pattern = %d{yyyy-MM-dd'T'HH:mm:ss'Z'} [%t] %-5p [%c] - %m%n  
appender.rolling.policies.type = Policies  
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy  
appender.rolling.policies.time.interval = 1  
appender.rolling.policies.time.modulate = true  
appender.rolling.strategy.type = DefaultRolloverStrategy  
appender.rolling.strategy.max = 20  
# 引入com.inspur.commmon包下的审计文件打印  
logger.rolling.name = com.inspur.common  
logger.rolling.level = info  
logger.rolling.additivity = false  
logger.rolling.appenderRef.rolling.ref = AuditFile  

 

4、测试

1) 查询日志级别接口

get  http://localhost:8080/loggers

 

response

  1. {  
  2.     "levels": [  
  3.         "OFF",  
  4.         "FATAL",  
  5.         "ERROR",  
  6.         "WARN",  
  7.         "INFO",  
  8.         "DEBUG",  
  9.         "TRACE"  
  10.     ],  
  11.     "loggers": {  
  12.         "ROOT": {  
  13.             "configuredLevel": "INFO",  
  14.             "effectiveLevel": "INFO"  
  15.         },  
  16.         "com.inspur.common": {  
  17.             "configuredLevel": "WARN",  
  18.             "effectiveLevel": "WARN"  
  19.         }
  20.     } 
  21. }

查询日志级别接口:

org.springframework.boot.actuate.logging.LoggersEndpoint.java

动态修改springboot日志级别_第2张图片

 

2) 设置日志级别接口

request:

post http://localhost:8080/loggers/{name}

body:

{

    "configuredLevel": "ERROR"

}

 

说明:

设置日志级别接口,在body中设置日志级别。

url中的name对应日志文件中的第一层的标签名称。name=ROOT对应rootLogger, name=com.inspur.common对应日志文件

 

设置日志级别接口:

org.springframework.boot.actuate.logging.LoggersEndpoint.java

 

动态修改springboot日志级别_第3张图片

  1. 测试用例

写一个接口,最基本的代码。如果打印信息符合设置的级别代表设置成功。判断条件可以不加。或者调用自己产品的代码中已经实现的接口来测试。集成log4j2不需要修改原有代码。

动态修改springboot日志级别_第4张图片

三、问题分析总结

1、设置日志级别不生效

现象:调用接口查询和设置日志级别都没有报错。设置新的日志级别后再调用查询接口返回的也是设置后的级别。但是控制台打印的日志级别并没有生效,还是打印启动时设置的日志级别及以上的日志信息。

 

分析:我们的原有代码中集成的是log4j日志框架,actuator接口已经不支持设置log4j日志级别了。调用设置级别的接口不报错,是因为是设置级别最终落到了默认的JavaLoggingSystem这个日志框架上了。但是代码中@Slf4j绑定的日志框架是log4j。所以没有生效。现在的项目中exclude了spring boot默认支持的logback而选用了老版本的log4j。

2、通过源码分析原因

actuator loggers接口代码:

org.springframework.boot.actuate.logging.LoggersEndpoint.java

这个loggers()就是对外提供的查询日志的接口。我们看到是通过this.loggingSystem这个对象的操作完成日志的查询和级别的配置。

动态修改springboot日志级别_第5张图片

 

进入LoggingSystem类。在应用启动时会调用LoggingSystem中的public static LoggingSystem get(ClassLoader classLoader)方法。这个方法会选择当前应用正在使用的日志实现框架。

动态修改springboot日志级别_第6张图片

动态修改springboot日志级别_第7张图片

 

上面两个图看到,会从SYSTEMS这个Map中筛选出当前应用的日志实现框架。当前支持的框架有三个:logback, log4j2LoggingSystem, JavaLoggingSystem。如果没有匹配到配置的日志框架,会默认选中JavaLoggingSystem。log4j不在支持范围内,所以调用actuator的loggers设置日志级别接口会落在JavaLoggingSystem日志框架上。

动态修改springboot日志级别_第8张图片

 

下面的logging包中也可以看到LoggingSystem支持的是java,log4j2和loback这三个日志实现框架

动态修改springboot日志级别_第9张图片

 

附:

level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(动态修改springboot日志级别)