SpringBoot不重启修改日志级别【Slf4j、Logback动态日志级别】

SpringBoot不重启修改日志级别【Slf4j、Logback动态日志级别】

前言

需求: 线上日志级别高,而定位问题时需要低级别日志便于分析问题

功能:不重启服务器,提供设置页,手动触发Slf4j 项目日志级别变化

扩展:可将此功能放入后台管理系统中,管理员只需,点选日志级别即可切换服务器的日志级别。

栗子 Like this:

在这里插入图片描述
或者使用命令行

curl 项目访问地址/sys/log/level/error
curl 项目访问地址/sys/log/level/warn
curl 项目访问地址/sys/log/level/info
curl 项目访问地址/sys/log/level/debug
curl 项目访问地址/sys/log/level/trace

查看日志状态

在这里插入图片描述

懒人如何实现?请copy如下代码 - _ -

Controller.java

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.Objects;
/**
 * @ IDE    :IntelliJ IDEA.
 * @ Date   :2019/11/6  19:40
 * @ Desc   :动态修改系统日志等级。
 */
@Slf4j
@RestController
@RequestMapping("/sys/log/level")
public class SysLogLevelController {
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    //日志等级常量
    //    final String[] levels = {"ERROR","WARN","INFO","DEBUG","TRACE"};
    final String[] levels = {"OFF","FATAL","ERROR","WARN","INFO","DEBUG","TRACE","ALL"};
    /**
     * 修改 根目录 日志级别
     * @param level                 日志级别
     * @return Result               返回结果
     * 栗子:
     *  curl [baseUrl]/sys/log/level/info
     *  curl [baseUrl]/sys/log/level/debug
     */
    @GetMapping("/{level}")
    public Result changeLevel(@PathVariable String level) {
        return Result.getMsgResult(setLogger("root",level));
    }
    /**
     * 修改 指定包 日志级别
     * @param level                 日志级别
     * @return Result               返回结果
     * 栗子:
     *  curl [baseUrl]/sys/log/level/info/[包名]
     *  curl [baseUrl]/sys/log/level/debug/[包名]
     */
    @GetMapping("/{level}/{packageName}")
    public Result changeLevel(@PathVariable String level,@PathVariable String packageName) {
       return Result.getMsgResult(setLogger(packageName,level));
    }
 /**
     * 测试当前日志等级
     * @param packageName           包名
     * @return Result               返回结果
     * 栗子:
     *  curl [baseUrl]/sys/log/level/test
     *  curl [baseUrl]/sys/log/level/test?packageName=[包名]
     */
    @GetMapping("/test")
    public Result testLevel(String packageName){
        log.trace("trace");
        log.debug("debug");
        log.info("info");
        log.warn("warn");
        log.error("error");
     StringBuilder msg = new StringBuilder();
       //全局日志等级 + 项目日志等级 + 具体包的日志等级
        msg.append(getLogger("root"));
        msg.append(getLogger(【SpringBoot启动类】.class.getPackage().getName()));
if (!StringUtils.isEmpty(packageName)){
            msg.append(getLogger(packageName));
        }
        return Result.getMsgResult(msg.toString());
    }
//--------------------------------------依赖方法------------------------------
    /**
     * 获取指定包日志级别             封装[设置日志级别+封装返回值信息]
     * @param packageName           包名
     * @return String               日志级别信息
     */
    private String getLogger(String packageName){
    return  packageName + "日志等级为:" + getLevel(packageName);
    }
 /**
     * 设置指定包日志级别             封装[日志级别检测+设置日志级别+封装返回值信息]
     * @param packageName           包名
     * @return String               日志级别信息
     */
    private String setLogger(String packageName,String level){
        boolean isAllowed = isAllowed(level);
        if (isAllowed){
            setLevel(packageName,level);
        }
        return isAllowed
                ? packageName+"日志等级更改为:"+level
                : packageName+"日志等级修改失败,可用值[ERROR,WARN,INFO,DEBUG,TRACE]";
    }
/**
     * 获取制定包的日志级别
     * @param packageName           包名
     * @return String               日志级别
     */
    private String getLevel(String packageName){
        Logger logger = loggerContext.getLogger(packageName);
//        ArrayUtil.hasNull(logger,logger.getLevel());//依赖Hutool工具
        return hasNull(logger,logger.getLevel())
                ? ""
                : logger.getLevel().toString();
    }
/**
     * 设置制定包的日志级别
     * @param packageName           包名
     * @param level                 日志等级
     */
    private void setLevel(String packageName,String level){
        loggerContext.getLogger(packageName).setLevel(Level.toLevel(level));
    }
/**
     * 判断是否是合法的日志级别
     * @param level                 日志等级
     * @return boolean
     */
    private boolean isAllowed(String level){
        return Arrays.asList(levels).contains(level.toUpperCase());
    }
/**
     * 判断多个对象中是否包含空对象
     * @param objects               多个对象
     * @return String               日志级别
     */
    private boolean hasNull(Object... objects) {
        if (Objects.nonNull(objects)) {
            for (Object element : objects) {
                if (null == element) {
                    return true;
                }
            }
        }
        return false;
    }

Result.java是web统一返回数据的类,不是必须要的。也可以自己实现。但是这里也提供一下。

Result.java

/**
 * @ IDE    :IntelliJ IDEA.
 * @ Date   :2019/9/27  16:44
 * @ Desc   :web 统一返回工具类
 */
import java.io.Serializable;
import java.time.LocalDateTime;
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer code;
    private String msg;
    private  T data;
    private String time;
    public Result(){
        setTime(LocalDateTime.now().toString());
    }
    public Result(Integer code){
        setCode(code).setTime(LocalDateTime.now().toString());
    }
    public Result(Integer code, String msg){
        setCode(code).setMsg(msg).setTime(LocalDateTime.now().toString());
    }
    public Result(Integer code, String msg, T data){
        setCode(code).setMsg(msg).setData(data).setTime(LocalDateTime.now().toString());
    }
    private static final int SUCCESS_CODE = 200;
    private static final int ERROR_CODE = 500;
    private static final String SUCCESS_MSG = "成功";
    private static final String ERROR_MSG = "失败";
    //成功返回值
    public static Result getSuccessResult() {
        return new Result(SUCCESS_CODE,SUCCESS_MSG);
    }
    public static <T> Result<T> getSuccessResult(T data) {
        return new Result<T>(SUCCESS_CODE,SUCCESS_MSG,data);
    }
    //错误返回值
    public static Result getErrorResult() {
        return new Result(ERROR_CODE,ERROR_MSG);
    }
    public static Result getErrorResult(String msg) {
        return new Result(ERROR_CODE,msg);
    }
    //自定义消息
    public static Result getMsgResult(String msg) {
        return new Result(SUCCESS_CODE,msg);
    }
    public static <T> Result<T> getMsgResult(String msg,T data) {
        return getMsgResult(msg).setData(data);
    }
    //自定义返回Code
    public static Result getCodeResult(Integer code,String msg) {
        return new Result(code,msg);
    }
    public static <T> Result<T> getCodeResult(Integer code,String msg,T data) {
        return getCodeResult(code,msg).setData(data);
    }
    public Integer getCode() {
        return code;
    }
    public Result<T> setCode(Integer code) {
        this.code = code;
        return this;
    }
    public String getMsg() {
        return msg;
    }
    public Result<T> setMsg(String msg) {
        this.msg = msg;
        return this;
    }
    public T getData() {
        return data;
    }
    public Result<T> setData(T data) {
        this.data = data;
        return this;
    }
    public String getTime() {
        return time;
    }
    public Result<T> setTime(String time) {
        this.time = time;
        return this;
    }
}

### Spring Boot 修改日志级别的方法 在 Spring Boot 中,可以通过多种方式修改日志级别。以下是几种常见的方法及其具体实现。 #### 方法一:静态配置文件设置日志级别 Spring Boot 支持通过 `application.properties` 或 `application.yml` 文件来静态定义日志级别。这种方式适用于开发阶段或部署前固定日志需求的情况。 ##### 使用 application.properties 配置 ```properties logging.level.root=INFO logging.level.org.springframework.web=DEBUG ``` 上述代码设置了根日志级别为 INFO,并将 `org.springframework.web` 包的日志级别调整为 DEBUG[^1]。 ##### 使用 application.yml 配置 ```yaml logging: level: root: INFO org.springframework.web: DEBUG ``` 此 YAML 片段同样实现了对同包路径下的日志级别分别设定的功能[^2]。 --- #### 方法二:动态修改日志级别(无需重启应用) 对于生产环境或者需要实时监控的应用场景,推荐使用动态修改日志级别的方案。这通常涉及 Actuator 组件的支持。 ##### 步骤说明 1. **引入 spring-boot-starter-actuator** 在项目的 `pom.xml` 文件中添加如下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ``` 2. **启用 /loggers 端点** 默认情况下 `/loggers` 端点会暴露给外部访问。如果希望允许 HTTP 请求调用,则需进一步开启 Web 端点支持。 在 `application.properties` 中加入以下内容: ```properties management.endpoints.web.exposure.include=loggers ``` 3. **发送请求更改日志级别** 可以通过 POST 请求向 `/actuator/loggers/{loggerName}` 发送 JSON 数据来更新指定 logger 的日志级别。例如: - 将 `com.example.demo` 的日志级别改为 TRACE: ```bash curl -X POST http://localhost:8080/actuator/loggers/com.example.demo \ -H 'Content-Type: application/json' \ -d '{"configuredLevel": "TRACE"}' ``` 这种方式能够实现在中断服务的情况下快速切换日志输出强度[^4]。 --- #### 方法三:编程式动态调整日志级别 除了利用内置的 Actuator 工具外,还可以借助 Logback 提供的 API 来手动编写逻辑完成相同目标。 下面展示了一个简单的例子用于演示如何通过 Java 编码形式改变某个特定类别的 logging threshold 值: ```java import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; public class LoggerLevelChanger { public static void setLoggerLevel(String packageName, String logLevel) { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); ch.qos.logback.classic.Logger logger = context.getLogger(packageName); switch(logLevel.toUpperCase()) { case "ERROR": logger.setLevel(Level.ERROR); break; case "WARN": logger.setLevel(Level.WARN); break; case "INFO": logger.setLevel(Level.INFO); break; case "DEBUG": logger.setLevel(Level.DEBUG); break; default : throw new IllegalArgumentException("Invalid Level"); } } } ``` 注意这种方法仅限于采用 SLF4JLogback 结合使用的场合下有效[^3]。 --- ### 总结 以上介绍了三种同的技术手段用来满足各种实际应用场景的需求——从基础到高级逐步深入探讨了有关于自定义化以及灵活性更高的解决方案。无论是初学者还是资深工程师都能找到适合自己项目特点的最佳实践途径。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值