关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
在软件开发与运维过程中,日志系统是我们监控应用状态、诊断问题的重要手段。然而,传统的日志系统往往需要重启应用才能更改日志级别,这在生产环境中通常是不可接受的。
动态修改日志级别的能力因此成为现代应用开发中的一项关键技术,它允许我们在运行时调整日志详细程度,既不中断服务又能精准获取所需信息。
02 痛点
为什么要动态修改日志级别?
程序员最讨厌别人不打日志,也最讨厌自己打日志。遇到线上问题时,总嫌弃日志打的太少无法定位问题。但是日志打印的多,运维这边又要收到报警了。源源不断的日志积累,瞬间沾满磁盘,甚至影响到正常的业务。
为了减少日志的打印,我们修改了日志的级别。不是很重要的日志设为DEBUG
级别,被认定为调试日志。正常答应的为INFO
级别,甚至WARN
级别。
为了应该调试,安全等场景动态修改日志级别可以给我们带来以下几个优点:
- 问题诊断与调试:当生产环境出现问题时,临时提高特定组件的日志级别可以获取更详细的执行信息,而无需重启服务
- 性能优化:在高负载情况下,降低日志级别可以减少I/O操作和序列化开销,提升系统性能
- 灵活监控:根据实际情况动态调整日志输出,平衡监控需求与存储成本
- 安全合规:敏感操作期间提高日志级别以满足审计要求,完成后恢复原有级别
03 实现方案与技术栈
本节介绍三种动态修改日志级别的方案:
- 自定义实现方案
- 配置Actuator暴露接口
- 集成
SpringBoot Admin
Spring Boot
默认级别是INFO
,正常访问时Debug
级别的日志是打印不出来的。我们定义一个专门打印日志的类:
java
@RequestMapping("/printLog")
public String printLog() {
log.debug("[DEBUG] Lever 日志:打印了......");
log.info("[INFO] Lever 日志:打印了......");
log.warn("[WARN] Lever 日志:打印了......");
return "日志已打印!";
}
3.1 自定义实现方案
自定实方案可以定制修改,灵活性较大。
修改核心代码
java
@RequestMapping("changeLogLever")
public String changeLogLever(String packageName, String lever) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = loggerContext.getLogger(packageName);
Level oldLevel = logger.getLevel();
if (oldLevel == null) {
oldLevel = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).getLevel();
}
logger.setLevel(Level.toLevel(lever));
log.debug("【DEBUG】日志级别从[{}]修改成[{}]级别了......", oldLevel, lever);
log.info("【INFO】日志级别从[{}]修改成[{}]级别了......",oldLevel, lever);
log.warn("【WARN】日志级别从[{}]修改成[{}]级别了......",oldLevel, lever);
return "日志级别修改成功.....";
}
关键类:ch.qos.logback.classic.LoggerContext
而LoggerContext
的获取是通过org.slf4j.LoggerFactory
得到的。
测试

还有另外的一种写法,通过Spring Boot
内部类来直接处理:
org.springframework.boot.logging.LoggingSystem
java
@Autowired
private LoggingSystem loggingSystem;
@RequestMapping("changeLogLever2")
public String changeLogLever2(String packageName, String lever) {
String oldLevel = loggingSystem.getLoggerConfiguration(packageName).getEffectiveLevel().name();
if (!StringUtils.hasText(oldLevel)) {
oldLevel = loggingSystem.getLoggerConfiguration(Logger.ROOT_LOGGER_NAME).getEffectiveLevel().name();
}
loggingSystem.setLogLevel(packageName, LogLevel.valueOf(lever.toUpperCase()));
log.debug("【DEBUG】日志级别从[{}]修改成[{}]级别了......", oldLevel, lever);
log.info("【INFO】日志级别从[{}]修改成[{}]级别了......", oldLevel, lever);
log.warn("【WARN】日志级别从[{}]修改成[{}]级别了......", oldLevel, lever);
System.out.println("------------------------------------------------------");
return "日志级别修改成功.....";
}
3.2 配置Actuator暴露接口
actuator
监控是Spring Boot
自带的监控。开启监控有一定的风险,小编分享过一篇关于监控邮箱配置的线上故障的文章已经讲过。
Maven依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
暴漏接口
management.endpoints.web.exposure.include
是用来暴露Spring Boot
自带的一些Web
接口的,可以用来查看和修改参数。
默认只有health
。

要精确配置可以配置loggers
,这里为了测试,暴漏所有的接口。线上要小心配置。
properties
management.endpoints.web.exposure.include=*
查看日志级别
通过GET
请求http://127.0.0.1:8080/actuator/loggers
,可以看到所有的包路径以及对应的日志级别:

查询具体的包的日志级别
只需要在连接后面跟上包名即可:
http://127.0.0.1:8080/actuator/loggers/包名
例如,我们要看com.simonking.boot.log.controller
报下的日志级别:

这个是因为小编在自定义方案实现的时候修改成的DEBUG
。
修改日志级别
与查看的请求相同,只不过变成POST
请求。并增加application/json
参数:
json
{"configuredLevel": "WARN"}
这里是要将日志级别变成WARN
级别。
curl
sh
curl --request POST \
--url http://127.0.0.1:8080/actuator/loggers/com.simonking.boot.log.controller.LogLevelController \
--data '{"configuredLevel": "WARN"}'
使用Apipost
执行:

请求测试

结果就只打印出了Warn
级别的日志。
3.3 集成SpringBoot Admin
spring-boot-admin
并不是Spring
官方提供的,而是有社区提供和维护的。

GitHub
地址:github.com/codecentric...
文档地址:docs.spring-boot-admin.com/3.5.2/docs/...
spring-boot-admin
由服务端和客户端组成:
- 服务端:监控平台
- 客户端:业务项目,引入
Admin
客户端,配置服务
spring-boot-admin
的服务端需要自行搭建,这里就演示了,下一期,我们专门介绍该监控平台。
客户端配置
xml
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.6.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
properties
spring.boot.admin.client.url=http://127.0.0.1:8081
management.endpoints.web.exposure.include=*
客户端管理
直接访问业务系统的域名和端口,进入日志配置:

这里可以随意修改每一个包的日志级别,我们修改成DEBUG
级别,顺便看下它调用的接口:


我们发现:这里调用的接口和配置Actuator
的接口非常类似。其实分析之后的结果,他们调用的事一个接口,只不过多了服务端内部的转发而已。
我们验证结果却是也生效了。

04 小结
动态修改日志级别是现代应用开发中的重要能力,它极大提升了系统的可观测性和运维效率。通过合理使用日志框架提供的功能或自定义实现,我们可以在不影响服务的前提下,精准控制日志输出,更好地平衡监控需求与系统性能。
实现这一功能时,需要充分考虑安全性、资源管理和分布式一致性等问题,确保系统的稳定性和可靠性。随着云原生和微服务架构的普及,动态日志管理将继续演进,为复杂分布式系统的运维提供更强有力的支持。
你更喜欢哪一种方式呢?