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; } }