在日常的开发过程中,为了方便定位问题,也为了甩锅,我们时常会打印一些日志,在开发,测试,生产各个环境中的日志级别可能不一样,在自己编码过程中为了方便调试打印了很多日志,但是生产中为了性能,为了节约存储资源,我们可能需要屏蔽掉一些不必要的日志,只保留一些关键的必要的日志。
我们在开发中一般使用如下代码打印日志:
package com.morris.spring.boot.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LogController {
private static final Logger log = LoggerFactory.getLogger(LogController.class);
public LogController() {
}
@GetMapping({"log"})
public String log() {
log.trace("log trace level test");
log.debug("log debug level test");
log.info("log info level test");
log.warn("log warn level test");
log.error("log error level test");
return "success";
}
}
使用slf4j的api来打印日志,底层具体日志的打印可以使用logback、log4j等框架。
slf4j中日志的级别优先级从高到低依次为:ERROR,WARN,INFO,DEBUG,TRACE。例如当日志级别为INFO时,只会打印比INFO级别高的日志。
如果在项目的运行过程中,想动态的修改日志的级别,不需要重启项目直接给日志降级或者升级该怎么实现呢?
从Spring Boot 1.5开始,Spring Boot Actuator组件就已提供动态修改日志级别的能力,废话不多说了,直接上代码吧!
引入依赖
引入spring-boot-starter-actuator
依赖,这里使用的是gradle,可自行转为maven:
implementation 'org.springframework.boot:spring-boot-starter-actuator:2.6.7'
开启日志端点配置
然后需要在配置文件中开启日志的端点:
# 由于Spring Boot 2.x默认只暴露 /health 以及 /info 端点,
# 而日志控制需要用到 /loggers 端点,故而需要设置将其暴露。当然把loggers替换成*也是可以的;开启所有!
management:
endpoints:
web:
exposure:
include: 'loggers'
# include: *
启动服务,访问http://127.0.0.1:8888/log
,可查看日志如下:
2023-07-07 10:15:51.298 INFO 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController : log info level test
2023-07-07 10:15:51.299 WARN 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController : log warn level test
2023-07-07 10:15:51.299 ERROR 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController : log error level test
可以看到默认的日志级别是INFO,比INFO优先级高的WARN和ERROR日志都会被打印出来。
查看指定包/类的日志级别
可以通过访问URL/actuator/loggers/
后加包名或者类名来查询指定包或者类的当前日志级别。
$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"
{"configuredLevel":null,"effectiveLevel":"INFO"}
$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller"
{"configuredLevel":null,"effectiveLevel":"INFO"}
修改包/类的日志级别
可以通过访问URL/actuator/loggers/
后加包名或者类名来修改指定包或者类的当前日志级别。
$ curl -X POST "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController" -H "Content-Type: application/json;charset=UTF-8" --data '{"configuredLevel":"debug"}'
再次查看日志级别:
$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}
再次访问http://127.0.0.1:8888/log
,可查看日志如下:
2023-07-07 10:22:03.252 DEBUG 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController : log debug level test
2023-07-07 10:22:03.253 INFO 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController : log info level test
2023-07-07 10:22:03.253 WARN 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController : log warn level test
2023-07-07 10:22:03.253 ERROR 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController : log error level test
可以看到日志级别已经被动态的修改为debug级别。
分析实现原理
Actuator有个约定,/actuator/xxx
端点的定义代码在xxxEndpoint
中。
所以/actuator/loggers
对应的类为org.springframework.boot.actuate.logging.LoggersEndpoint
。
@Endpoint(id = “loggers”) 用来描述Spring Boot Actuator的端点,这样就会产生一个/actuator/loggers的路径,它类似于Spring MVC的@RequestMapping(“loggers”) 。
@Endpoint(id = "loggers")
public class LoggersEndpoint {
private final LoggingSystem loggingSystem;
private final LoggerGroups loggerGroups;
/**
* Create a new {@link LoggersEndpoint} instance.
* @param loggingSystem the logging system to expose
* @param loggerGroups the logger group to expose
*/
public LoggersEndpoint(LoggingSystem loggingSystem, LoggerGroups loggerGroups) {
Assert.notNull(loggingSystem, "LoggingSystem must not be null");
Assert.notNull(loggerGroups, "LoggerGroups must not be null");
this.loggingSystem = loggingSystem;
this.loggerGroups = loggerGroups;
}
Spring Boot Actuator还提供了其他操作,如下表:
Operation | HTTP method |
---|---|
@ReadOperation | GET |
@WriteOperation | POST |
@DeleteOperation | DELETE |
查看指定包/类的日志级别
org.springframework.boot.actuate.logging.LoggersEndpoint#loggerLevels
@ReadOperation
public LoggerLevels loggerLevels(@Selector String name) {
Assert.notNull(name, "Name must not be null");
LoggerGroup group = this.loggerGroups.get(name);
if (group != null) {
return new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers());
}
LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name);
return (configuration != null) ? new SingleLoggerLevels(configuration) : null;
}
LoggingSystem有四个实现类:
// 适用于java.util.logging的LoggingSystem
org.springframework.boot.logging.java.JavaLoggingSystem
//适用于Log4j2的LoggingSystem
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem
//适用于logback的LoggingSystem
org.springframework.boot.logging.logback.LogbackLoggingSystem
// 啥都不干的LoggingSystem
org.springframework.boot.logging.LoggingSystem.NoOpLoggingSystem
Spring Boot 2.x中,默认使用Logback,因此进入到LogbackLoggingSystem中。
org.springframework.boot.logging.logback.LogbackLoggingSystem#getLoggerConfiguration(java.lang.String)
public LoggerConfiguration getLoggerConfiguration(String loggerName) {
String name = getLoggerName(loggerName);
LoggerContext loggerContext = getLoggerContext();
return getLoggerConfiguration(loggerContext.exists(name));
}
private LoggerConfiguration getLoggerConfiguration(ch.qos.logback.classic.Logger logger) {
if (logger == null) {
return null;
}
LogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());
LogLevel effectiveLevel = LEVELS.convertNativeToSystem(logger.getEffectiveLevel());
String name = getLoggerName(logger.getName());
return new LoggerConfiguration(name, level, effectiveLevel);
}
修改包/类的日志级别
org.springframework.boot.actuate.logging.LoggersEndpoint#configureLogLevel
public void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) {
Assert.notNull(name, "Name must not be empty");
LoggerGroup group = this.loggerGroups.get(name);
if (group != null && group.hasMembers()) {
group.configureLogLevel(configuredLevel, this.loggingSystem::setLogLevel);
return;
}
this.loggingSystem.setLogLevel(name, configuredLevel);
}
org.springframework.boot.logging.logback.LogbackLoggingSystem#setLogLevel
public void setLogLevel(String loggerName, LogLevel level) {
ch.qos.logback.classic.Logger logger = getLogger(loggerName);
if (logger != null) {
logger.setLevel(LEVELS.convertSystemToNative(level));
}
}
其实就是Spring Boot使用了Logback的API,ch.qos.logback.classic.Logger.setLevel实现日志级别的修改。
自己实现动态修改日志级别
在实际的开发过程中,应用是不会暴露出/actuator/loggers
端点,因为这样会直接暴露在公网上,有安全风险,所以我们可以自己写一个Controller来修改日志级别。文章来源:https://www.toymoban.com/news/detail-763487.html
package com.morris.spring.boot.controller;
import org.springframework.boot.actuate.logging.LoggersEndpoint;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 动态修改日志级别
*/
@RequestMapping("loggers")
@RestController
public class LoggersController {
private final LoggingSystem loggingSystem = LoggingSystem.get(LoggingSystem.class.getClassLoader());
@GetMapping("/level")
public Object getLevel(String name) {
LoggerConfiguration configuration = loggingSystem.getLoggerConfiguration(name);
return (configuration != null) ? new LoggersEndpoint.SingleLoggerLevels(configuration) : null;
}
@PostMapping("/level")
public void setLevel(String name, LogLevel level) {
loggingSystem.setLogLevel(name, level);
}
}
测试,注意设置level的时候使用大写:文章来源地址https://www.toymoban.com/news/detail-763487.html
$ curl http://127.0.0.1:8888/loggers/level
{"configuredLevel":"INFO","effectiveLevel":"INFO"}
$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":null,"effectiveLevel":"INFO"}
$ curl -X POST "http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController&level=DEBUG"
$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}
到了这里,关于【springboot】如何动态修改日志级别???的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!