支持运行时动态修改日志级别
背景介绍
在系统上线后,一般会将日志级别控制在一定范围内,因为,大量的输出日志会影响系统的性能。当系统出现问题后,可能需要变更日志级别,在关键节点输出更多的日志,方便排查问题。但是,如果通过修改配置去变更日志级别,需要重新启动应用服务,此时就需要支持系统运行时动态修改日志级别。
解决方案
使用springboot的LoggingSystem.setLogLevel动态修改日志级别
- 编写日志级别更新类
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);
}
}
- 编写
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<>();
}
}
- 调用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"
}