支持运行时动态修改全局、模块、类日志级别

支持运行时动态修改日志级别

背景介绍

在系统上线后,一般会将日志级别控制在一定范围内,因为,大量的输出日志会影响系统的性能。当系统出现问题后,可能需要变更日志级别,在关键节点输出更多的日志,方便排查问题。但是,如果通过修改配置去变更日志级别,需要重新启动应用服务,此时就需要支持系统运行时动态修改日志级别。

解决方案

使用springboot的LoggingSystem.setLogLevel动态修改日志级别

  1. 编写日志级别更新类LogLevelOperator,提供"更新全局日志级别"和"按包名/类名更新日志级别"两种方法:
/**
 * 日志级别动态更新器
 */
@Component
public class LogLevelOperator {

    public static final String ROOT_LOGGER_NAME = "ROOT";

    private static final Map<String, LogLevel> LEVELS = new HashMap<>();

    static {
        LEVELS.put("trace", LogLevel.TRACE);
        LEVELS.put("debug", LogLevel.DEBUG);
        LEVELS.put("info", LogLevel.INFO);
        LEVELS.put("warn", LogLevel.WARN);
        LEVELS.put("error", LogLevel.ERROR);
        LEVELS.put("fatal", LogLevel.FATAL);
        LEVELS.put("off", LogLevel.OFF);
    }

    @Autowired
    public LoggingSystem loggingSystem;

    /**
     * 更新全局日志级别
     *
     * @param logLevel 日志级别,trace、debug、info、warn、fatal、off
     */
    public void updateRootLogLevel(String logLevel) {
        updateLogLevel(ROOT_LOGGER_NAME, logLevel);
    }

    /**
     * 按包名或类名更新日志级别
     *
     * @param loggerName 包名或类名,例如:com.szkingdom或com.szkingdom.MyTestClass,
     * 									 若为空或ROOT,则默认更新全局日志级别
     * @param logLevel   日志级别,trace、debug、info、warn、fatal、off
     */
    public void updateLogLevel(String loggerName, String logLevel) {
        // 若loggerName为空,则默认使用ROOT_LOGGER_NAME,将更新全局日志级别
        String name = loggerName;
        if (!StringUtils.hasText(name) || ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            name = ROOT_LOGGER_NAME;
        }

        // 更新日志级别
        LogLevel level = LEVELS.get(logLevel);
        if (level == null) {
            throw new RuntimeException("[" + loggerName + "]模块更新日志级别失败,不支持[" + logLevel + "]的日志级别,仅支持trace、debug、info、warn、fatal、off六种日志级别");
        }
        loggingSystem.setLogLevel(name, level);
    }
}
  1. 编写Controller类,调用LogLevelOperator类里的方法来更新日志级别
@RestController
public class LogLevelController {

    @Autowired
    public LogLevelOperator logLevelOperator;

    /**
     * 按包名或类名更新日志级别
     *
     * @param vo 包名/类名,待更新的日志级别
     * @return 是否更新成功
     */
    @PostMapping("updateLogLevel")
    public Result<String> updateLogLevel(@RequestBody LogLevelVo vo) {
        logLevelOperator.updateLogLevel(vo.getLoggerName(), vo.getLogLevel());
        return new Result<>();
    }

    /**
     * 更新全局的日志级别
     *
     * @param vo 日志级别设置信息
     * @return 是否更新成功
     */
    @PostMapping("updateRootLogLevel")
    public Result<String> updateRootLogLevel(@RequestBody LogLevelVo vo) {
        logLevelOperator.updateRootLogLevel(vo.getLogLevel());
        return new Result<>();
    }
}

  1. 调用Controller层接口来进行日志级别的动态更新
### 按包名更新日志级别
POST http://localhost:8080/updateLogLevel
Content-Type: application/json

{
  "logLevel":"debug",
  "loggerName":"com.szkingdom"
}

### 按类名更新日志级别
POST http://localhost:8080/updateLogLevel
Content-Type: application/json

{
  "logLevel":"debug",
  "loggerName":"com.szkingdom.MyTestClass"
}

### 修改全局日志级别
POST http://localhost:8080/updateRootLevel
Content-Type: application/json

{
  "logLevel":"debug",
}

使用Actuator工具动态修改日志级别

1.导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.配置

management:
  endpoints:
    web:
      exposure:
        # 默认值访问health,info端点 日志级别控制需要使用/loggers端点, 用*可以包含全部端点
        include: "*"
      # 修改访问路径 2.0之前默认是/; 2.0默认是/actuator可以通过这个属性值修改
      base-path: /actuator
  endpoint:
    shutdown:
      enabled: true #打开shutdown端点
    health:
      show-details: always #获得健康检查中所有指标的详细信息
  # actuator端口 如果不配置做默认使用上面8080端口
  server:
    port: 8080

3.接口调用

### 使用 Actuator 修改日志级别
POST http://localhost:8080/actuator/loggers/[package_name]
Content-Type: application/json

{
  "configuredLevel": "logLevel"
}
2 个赞

这一段伟大的代码