0


【springboot】如何动态修改日志级别???

在日常的开发过程中,为了方便定位问题,也为了甩锅,我们时常会打印一些日志,在开发,测试,生产各个环境中的日志级别可能不一样,在自己编码过程中为了方便调试打印了很多日志,但是生产中为了性能,为了节约存储资源,我们可能需要屏蔽掉一些不必要的日志,只保留一些关键的必要的日志。

我们在开发中一般使用如下代码打印日志:

packagecom.morris.spring.boot.controller;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassLogController{privatestaticfinalLogger log =LoggerFactory.getLogger(LogController.class);publicLogController(){}@GetMapping({"log"})publicStringlog(){
        log.trace("log trace level test");
        log.debug("log debug level test");
        log.info("log info level test");
        log.warn("log warn level test");
        log.error("log error level test");return"success";}}

使用slf4j的api来打印日志,底层具体日志的打印可以使用logback、log4j等框架。

slf4j中日志的级别优先级从高到低依次为:ERROR,WARN,INFO,DEBUG,TRACE。例如当日志级别为INFO时,只会打印比INFO级别高的日志。

如果在项目的运行过程中,想动态的修改日志的级别,不需要重启项目直接给日志降级或者升级该怎么实现呢?

从Spring Boot 1.5开始,Spring Boot Actuator组件就已提供动态修改日志级别的能力,废话不多说了,直接上代码吧!

引入依赖

引入

spring-boot-starter-actuator

依赖,这里使用的是gradle,可自行转为maven:

implementation 'org.springframework.boot:spring-boot-starter-actuator:2.6.7'

开启日志端点配置

然后需要在配置文件中开启日志的端点:

# 由于Spring Boot 2.x默认只暴露 /health 以及 /info 端点,# 而日志控制需要用到 /loggers 端点,故而需要设置将其暴露。当然把loggers替换成*也是可以的;开启所有!
management:
  endpoints:
    web:
      exposure:
        include: 'loggers'# include: *

启动服务,访问

http://127.0.0.1:8888/log

,可查看日志如下:

2023-07-07 10:15:51.298  INFO 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log info level test2023-07-07 10:15:51.299  WARN 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log warn level test2023-07-07 10:15:51.299 ERROR 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log error level test

可以看到默认的日志级别是INFO,比INFO优先级高的WARN和ERROR日志都会被打印出来。

查看指定包/类的日志级别

可以通过访问URL

/actuator/loggers/

后加包名或者类名来查询指定包或者类的当前日志级别。

$ curl"http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"{"configuredLevel":null,"effectiveLevel":"INFO"}

$ curl"http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller"{"configuredLevel":null,"effectiveLevel":"INFO"}

修改包/类的日志级别

可以通过访问URL

/actuator/loggers/

后加包名或者类名来修改指定包或者类的当前日志级别。

$ curl-X POST "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"-H"Content-Type: application/json;charset=UTF-8"--data'{"configuredLevel":"debug"}'

再次查看日志级别:

$ curl"http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}

再次访问

http://127.0.0.1:8888/log

,可查看日志如下:

2023-07-07 10:22:03.252 DEBUG 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log debug level test2023-07-07 10:22:03.253  INFO 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log info level test2023-07-07 10:22:03.253  WARN 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log warn level test2023-07-07 10:22:03.253 ERROR 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log error level test

可以看到日志级别已经被动态的修改为debug级别。

分析实现原理

Actuator有个约定,

/actuator/xxx

端点的定义代码在

xxxEndpoint

中。

所以

/actuator/loggers

对应的类为

org.springframework.boot.actuate.logging.LoggersEndpoint

@Endpoint(id = “loggers”) 用来描述Spring Boot Actuator的端点,这样就会产生一个/actuator/loggers的路径,它类似于Spring MVC的@RequestMapping(“loggers”) 。

@Endpoint(id ="loggers")publicclassLoggersEndpoint{privatefinalLoggingSystem loggingSystem;privatefinalLoggerGroups loggerGroups;/**
     * Create a new {@link LoggersEndpoint} instance.
     * @param loggingSystem the logging system to expose
     * @param loggerGroups the logger group to expose
     */publicLoggersEndpoint(LoggingSystem loggingSystem,LoggerGroups loggerGroups){Assert.notNull(loggingSystem,"LoggingSystem must not be null");Assert.notNull(loggerGroups,"LoggerGroups must not be null");this.loggingSystem = loggingSystem;this.loggerGroups = loggerGroups;}

Spring Boot Actuator还提供了其他操作,如下表:
OperationHTTP method@ReadOperationGET@WriteOperationPOST@DeleteOperationDELETE

查看指定包/类的日志级别

org.springframework.boot.actuate.logging.LoggersEndpoint#loggerLevels

@ReadOperationpublicLoggerLevelsloggerLevels(@SelectorString name){Assert.notNull(name,"Name must not be null");LoggerGroup group =this.loggerGroups.get(name);if(group !=null){returnnewGroupLoggerLevels(group.getConfiguredLevel(), group.getMembers());}LoggerConfiguration configuration =this.loggingSystem.getLoggerConfiguration(name);return(configuration !=null)?newSingleLoggerLevels(configuration):null;}

LoggingSystem有四个实现类:

// 适用于java.util.logging的LoggingSystem
org.springframework.boot.logging.java.JavaLoggingSystem
//适用于Log4j2的LoggingSystem
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem
//适用于logback的LoggingSystem
org.springframework.boot.logging.logback.LogbackLoggingSystem
// 啥都不干的LoggingSystem
org.springframework.boot.logging.LoggingSystem.NoOpLoggingSystem

Spring Boot 2.x中,默认使用Logback,因此进入到LogbackLoggingSystem中。

org.springframework.boot.logging.logback.LogbackLoggingSystem#getLoggerConfiguration(java.lang.String)

publicLoggerConfigurationgetLoggerConfiguration(String loggerName){String name =getLoggerName(loggerName);LoggerContext loggerContext =getLoggerContext();returngetLoggerConfiguration(loggerContext.exists(name));}privateLoggerConfigurationgetLoggerConfiguration(ch.qos.logback.classic.Logger logger){if(logger ==null){returnnull;}LogLevel level =LEVELS.convertNativeToSystem(logger.getLevel());LogLevel effectiveLevel =LEVELS.convertNativeToSystem(logger.getEffectiveLevel());String name =getLoggerName(logger.getName());returnnewLoggerConfiguration(name, level, effectiveLevel);}

修改包/类的日志级别

org.springframework.boot.actuate.logging.LoggersEndpoint#configureLogLevel

publicvoidconfigureLogLevel(@SelectorString name,@NullableLogLevel configuredLevel){Assert.notNull(name,"Name must not be empty");LoggerGroup group =this.loggerGroups.get(name);if(group !=null&& group.hasMembers()){
        group.configureLogLevel(configuredLevel,this.loggingSystem::setLogLevel);return;}this.loggingSystem.setLogLevel(name, configuredLevel);}

org.springframework.boot.logging.logback.LogbackLoggingSystem#setLogLevel

publicvoidsetLogLevel(String loggerName,LogLevel level){ch.qos.logback.classic.Logger logger =getLogger(loggerName);if(logger !=null){
        logger.setLevel(LEVELS.convertSystemToNative(level));}}

其实就是Spring Boot使用了Logback的API,ch.qos.logback.classic.Logger.setLevel实现日志级别的修改。

自己实现动态修改日志级别

在实际的开发过程中,应用是不会暴露出

/actuator/loggers

端点,因为这样会直接暴露在公网上,有安全风险,所以我们可以自己写一个Controller来修改日志级别。

packagecom.morris.spring.boot.controller;importorg.springframework.boot.actuate.logging.LoggersEndpoint;importorg.springframework.boot.logging.LogLevel;importorg.springframework.boot.logging.LoggerConfiguration;importorg.springframework.boot.logging.LoggingSystem;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;/**
 * 动态修改日志级别
 */@RequestMapping("loggers")@RestControllerpublicclassLoggersController{privatefinalLoggingSystem loggingSystem =LoggingSystem.get(LoggingSystem.class.getClassLoader());@GetMapping("/level")publicObjectgetLevel(String name){LoggerConfiguration configuration = loggingSystem.getLoggerConfiguration(name);return(configuration !=null)?newLoggersEndpoint.SingleLoggerLevels(configuration):null;}@PostMapping("/level")publicvoidsetLevel(String name,LogLevel level){
        loggingSystem.setLogLevel(name, level);}}

测试,注意设置level的时候使用大写:

$ curl http://127.0.0.1:8888/loggers/level
{"configuredLevel":"INFO","effectiveLevel":"INFO"}

$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":null,"effectiveLevel":"INFO"}

$ curl-X POST "http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController&level=DEBUG"

$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}
标签: spring boot java spring

本文转载自: https://blog.csdn.net/u022812849/article/details/131593538
版权归原作者 morris131 所有, 如有侵权,请联系我们删除。

“【springboot】如何动态修改日志级别???”的评论:

还没有评论