需求: 线上日志级别高,而定位问题时需要低级别日志便于分析问题
功能:不重启服务器,提供设置页,手动触发Slf4j 项目日志级别变化
扩展:可将此功能放入后台管理系统中,管理员只需,点选日志级别即可切换服务器的日志级别。
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
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统一返回数据的类,不是必须要的。也可以自己实现。但是这里也提供一下。
/**
* @ 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;
}
}
推荐阅读
一个AOP小专题
{
"author": "大火yzs",
"title": "SpringBoot不重启修改日志级别【Slf4jj动态日志级别】",
"tag": "动态日志,不重启服务",
"createTime": "2020-05-19 12:35"
}