SpringBoot不重啓修改日誌級別【Slf4jj動態日誌級別】
前言
需求: 線上日誌級別高,而定位問題時需要低級別日誌便於分析問題
功能:不重啓服務器,提供設置頁,手動觸發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();
/**
* 測試當前日誌等級接口
* @param packageName 包名
* @return Result 返回結果
* 栗子:
* curl [baseUrl]/sys/log/level/test
*/
@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 (packageName!=null && !packageName.isEmpty()){
msg.append(getLogger(packageName));
}
return Result.getMsgResult(msg.toString());
}
/**
* 修改日誌級別接口
* @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 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 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);
return hasNull(logger,logger.getLevel())
? ""
: logger.getLevel().toString();
}
private boolean hasNull(Object... objects) {
if (Objects.nonNull(objects)) {
for (Object element : objects) {
if (null == element) {
return true;
}
}
}
return false;
}
/**
* 設置制定包的日誌級別
* @param packageName 包名
* @param level 日誌等級
*/
private void setLevel(String packageName,String level){
loggerContext.getLogger(packageName).setLevel(Level.toLevel(level));
}
// final String[] levels = {"ERROR","WARN","INFO","DEBUG","TRACE"};
final String[] levels = {"OFF","FATAL","ERROR","WARN","INFO","DEBUG","TRACE","ALL"};
/**
* 判斷是否是合法的日誌級別
* @param level 日誌等級
* @return boolean
*/
private boolean isAllowed(String level){
return Arrays.asList(levels).contains(level.toUpperCase());
}
}
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;
}
}
推薦閱讀
一個AOP小專題
{
"author": "大火yzs",
"title": "SpringBoot不重啓修改日誌級別【Slf4jj動態日誌級別】",
"tag": "動態日誌,不重啓服務",
"createTime": "2020-05-19 12:35"
}