线上系统的日志级别一般使用INFO或者WARN,但是在遇到问题的时候,希望拿到更低级别的日志,方便定位问题。所以需要一种动态调整日志级别的方法。
常用方法
- 开启logback的自动扫描更新
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
- 自定义api
但是这种方式只能逐台服务器来更新,比较麻烦,也因为负载均衡的原因,也不容易控制
@RequestMapping(value = "/setlevel")
public String updateLogbackLevel(@RequestParam(value = "level") String level,
@RequestParam(value = "packageName", defaultValue = "-1") String packageName) throws Exception {
ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = null
if (packageName.equals("-1")) {
// 默认值-1,更改全局日志级别;否则按传递的包名或类名修改日志级别。
logger = loggerContext.getLogger("root")
} else {
logger = loggerContext.getLogger(packageName)
}
logger.setLevel(ch.qos.logback.classic.Level.toLevel(level));
return logger.getLevel();
}
- Spring Boot引入Actuator
修改日志级别 通过http://localhost:8080/actuator/{loggers}
端点提供的 POST 请求,修改包路径com.xxx.aa的日志级别为DEBUG:
发送POST 请求到http://localhost:8080/actuator/loggers/com.xxx.aa
,其中请求 Body 的内容如下:
{
"configuredLevel": "DEBUG"
}
- 集成Spring Cloud Admin来动态修改配置
如果使用Spring Cloud Admin作为配置中心的话,这种方式是最推荐的,但是在实际项目中,Spring Cloud Admin用的比较少
配置中心实时下发(推荐)
很多开源的配置中心都支持@Value
配置的实时更新,比如百度disconf
,携程Apollo
。使用配置中心可以让所有的服务器同步更新日志级别。
@Slf4j
@Configuration
public class TenmaoConfiguration {
public static final Gson GSON = new Gson();
private static final Type LOGGER_LEVEL_TYPE = new TypeToken<List<LoggerLevel>>() {
}.getType();
@Value("${logback.levels}")
public void updateLogbackLevel(String levels) throws Exception {
log.info("logback.levels: {}", levels);
List<LoggerLevel> logbackLevels = GSON.fromJson(levels, LOGGER_LEVEL_TYPE);
if (CollectionUtils.isEmpty(logbackLevels)) {
return;
}
logbackLevels.forEach(LoggerLevel::checkAndConvert);
ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory();
for (LoggerLevel entry : logbackLevels) {
Logger logger = loggerContext.getLogger(entry.getLoggerName());
logger.setLevel(entry.getLevel());
}
}
@Data
private static class LoggerLevel {
private String loggerName;
private String levelName;
private Level level;
public void checkAndConvert() {
if (!Strings.isNullOrEmpty(levelName)) {
level = Level.valueOf(levelName);
} else {
level = null;
}
}
}
}
- 配置内容示例(json格式的字符串)
[
{
"loggerName": "root",
"levelName": "INFO"
},{
"loggerName": "com.tenmao.mvc.controller",
"levelName": "DEBUG"
}
]
网友评论