Spring boot动态修改日志级别

排查问题是开发人员经常要做的事情,日志是我们常用的排查问题手段,在生产环境我们通常会把日志级别调高,屏蔽我们不关心的日志,那么我们是怎么处理的呢,在spring boot中又有没有更好的处理方案呢

一、低版本处理方式

可能我们在低版本中是这样处理的:

@SuppressWarnings("unckecked")
   @GetMapping("/setLogger")
   public Result<String> setLogger(String level) {
       Result<String> result = new Result<>();

       Level logLevel = "1".equals(level) ? Level.ERROR : Level.DEBUG;
       LoggerContext ctx = (LoggerContext) LogManager.getContext(false);

       org.apache.logging.log4j.core.config.Configuration config = ctx.getConfiguration();

       Map<String, LoggerConfig> loggerConfigs = config.getLoggers();
       loggerConfigs.forEach((name, loggerConfig) -> loggerConfig.setLevel(logLevel));

       ctx.updateLoggers(config);
       return result.setData("日志级别调整到"+logLevel);
   }

二、Spring Boot 处理方式

spring boot 1.5之后我们可以用Spring Boot Actuator处理:

1、添加依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2、添加配置暴露loggers,默认只暴露health和info
server:
  port: 8088
spring:
  application:
    name: logtest
management:
  endpoints:
    web:
      exposure:
        include:
          - info
          - health
          - loggers #默认只暴露 /health 以及 /info 端点
3、写测试demo并
package com.jarvan.test.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Jarvan
 */
@RestController
@Slf4j
public class LogController {

    @GetMapping("/testLog")
    public String testLog() {
        log.debug("这是一个debug日志...");
        return "test log";
    }
}
4、查看当前应用各包/类的日志级别

upload successful

5、查看指定包/类日志详情

访问http://localhost:8088/actuator/loggers/com.jarvan.test.controller

upload successful

6、调用http://localhost:8088/testLog

因为我们日志级别是info所以debug是不会输出的,下面开始改日志级别

7、修改指定包/类日志级别

cmd 运行如下命令或使用postman类似工具

curl "http://localhost:8088/actuator/loggers/com.jarvan.test.controller" -H "Content-Type: application/json" -d "{\"configuredLevel\":\"debug\"}" -X POST

upload successful

8、查看com.jarvan.test.controller包级别已经更改为DEBUG
http://localhost:8088/actuator/loggers/com.jarvan.test.controller

upload successful

9、验证日志级别

再次调用http://localhost:8088/testLog并查看控制台是否有输出

三、原理简析

Actuator约定/actuator/xxx 端点的代码定义在 xxxEndpoint 里面,所以我们找到LoggersEndpoint,它在 org.springframework.boot.actuate.logging 包下面

upload successful

其中, EndpointWriteOperation@Selector 都是Spring Boot 2.0开始提供的新注解。

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

@WriteOperation 表示这是一个写操作,它类似于Spring MVC的 @PostMapping

Spring Boot Actuator还提供了其他操作,如下表:

OperationHTTP method
@ReadOperationGET
@WriteOperationPOST
@DeleteOperationDELETE

@Selector 用于筛选 @Endpoint 注解返回值的子集,它类似于Spring MVC的 @PathVariable

这样,上面的代码就很好理解了—— configureLogLevel 方法里面就一行代码 :this.loggingSystem.setLogLevel(name, configuredLevel); ,发送POST请求后,name就是我们传的包名或者类名,configuredLevel就是我们传的消息体。

然后我们点进这个方法中看具体的实现

upload successful

setLogLevel一共有四种实现

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

找个实现点进去

public void setLogLevel(String loggerName, LogLevel logLevel) {
        Level level = (Level)LEVELS.convertSystemToNative(logLevel);
        LoggerConfig logger = this.getLogger(loggerName);
        if (logger == null) {
            logger = new LoggerConfig(loggerName, level, true);
            this.getLoggerContext().getConfiguration().addLogger(loggerName, logger);
        } else {
            logger.setLevel(level);
        }

        this.getLoggerContext().updateLoggers();
    }

我们发现Spring Boot本质上还是使用了log底层API的LoggerConfig.setLevel()方法实现日志级别的修改

你可能会好奇,LoggingSystem有这么多实现类,Spring Boot怎么知道什么情况下用什么LoggingSystem呢?可在 org.springframework.boot.logging.LoggingSystem 找到类似如下代码:

upload successful

由代码不难发现,其实就是构建了一个名为 SYSTEMS 的map,作为各种日志系统的字典;然后在 get 方法中,看应用是否加载了map中的类;如果加载了,就通过反射,初始化响应 LoggingSystem 。例如:Spring Boot发现当前应用加载了 ch.qos.logback.core.Appender ,就去实例化 org.springframework.boot.logging.logback.LogbackLoggingSystem

四、可视化界面

Spring Boot Admin配置请移步 Spring Boot Admin配置可视化页面

本文是使用 curl 手动发送 POST 请求手动修改日志级别的,该方式不适用生产,因为很麻烦,容易出错。生产环境,建议根据Actuator提供的RESTful API定制界面,或使用 Spring Boot Admin ,可视化修改日志级别,如下图所示:

想修改哪个包/类的日志级别,直接点击即可。

upload successful

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值