SpringBoot 動態(tài)設(shè)置 logback 日志的級別
SpringBoot 默認(rèn)采用 Logback 日志作為記錄日志的框架。在項目中,一般分為 dev 環(huán)境(開發(fā)環(huán)境)、test環(huán)境(測試環(huán)境)和 prd 環(huán)境(生產(chǎn)環(huán)境)。而一般開發(fā)環(huán)境和測試環(huán)境可以把日志級別設(shè)置成 info 級別,方便在聯(lián)調(diào)與測試中解決遇到的bug,但是生產(chǎn)環(huán)境因為存在大量的業(yè)務(wù),如果采用 info 級別的日志, 那么每一筆交易或者業(yè)務(wù)都打印大量的日志。這樣的花需要大量的磁盤空間來保存日志。如果日志需要保存一年半載,或者有些業(yè)務(wù)場景,例如財務(wù)數(shù)據(jù)的日志需要保存更久。將給公司造成很大的財務(wù)浪費。今天分享一個小方案,動態(tài)改變?nèi)罩镜募墑e,方便在生產(chǎn)環(huán)境也能方便快捷的從 warn 或者 error 級別切換到 debug 或者 info 級別。
0x01:pom.xml 引入依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.olive</groupId>
<artifactId>valid-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath />
</parent>
<name>valid-demo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
0x02:logbak-spring.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:當(dāng)此屬性設(shè)置為true時,配置文件如果發(fā)生改變,將會被重新加載,默認(rèn)值為true。
scanPeriod:設(shè)置監(jiān)測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認(rèn)單位是毫秒當(dāng)scan為true時,此屬性生效。默認(rèn)的時間間隔為1分鐘。
debug:當(dāng)此屬性設(shè)置為true時,將打印出logback內(nèi)部日志信息,實時查看logback運行狀態(tài)。默認(rèn)值為false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- ch.qos.logback.core.ConsoleAppender 表示控制臺輸出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志輸出格式:
%d表示日期時間,
%thread表示線程名,
%-5level:級別從左顯示5個字符寬度
%logger{50} 表示logger名字最長50個字符,否則按照句點分割。
%msg:日志消息,
%n是換行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<root level="info">
<!-- 控制臺輸出日志-->
<appender-ref ref="stdout" />
</root>
</configuration>
為了演示,這里只配置了一個 rootLogger
0x03:編寫 Controller
該 Controller 主要包含以下三個API
主要框架
package com.olive.controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
@RestController
public class LoggerController {
private final static Logger logger = LoggerFactory.getLogger(LoggerController.class);
// TODO
}打印各日志級別的日志
@RequestMapping("/logger/print")
public Map loggerPrint(){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
logger.debug("loggerPrint debug>>>>");
logger.info("loggerPrint info>>>>");
logger.warn("loggerPrint warn>>>>");
logger.error("loggerPrint error>>>>");
return result;
}
打印日志對象 Logger
@RequestMapping("/logger/printAllLogger")
public Map printAllLogger(){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
List<ch.qos.logback.classic.Logger> loggers = loggerContext.getLoggerList();
Iterator<ch.qos.logback.classic.Logger> iter = loggers.iterator();
System.out.println("printAllLogger begin>>>>>>>>");
while(iter.hasNext()){
System.out.println(iter.next().getName());
}
System.out.println("printAllLogger end>>>>>>>>");
return result;
}
該方法打印所有存在的日志對象 Logger
設(shè)置 ROOT 日志對象的日志級別
@RequestMapping("/logger/level")
public Map loggerLevelChange(String level){
Map result = new HashMap();
result.put("code", 200);
result.put("msg", "success");
String loggerFactoryClassStr = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr();
System.out.println("loggerFactoryClassStr>>>>" + loggerFactoryClassStr);
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
ch.qos.logback.classic.Logger logger = loggerContext.getLogger("ROOT");
switch (level) {
case "debug":
logger.setLevel(Level.DEBUG);
break;
case "info":
logger.setLevel(Level.INFO);
break;
case "warn":
logger.setLevel(Level.WARN);
break;
case "error":
logger.setLevel(Level.ERROR);
break;
default:
break;
}
return result;
}
0x04:編寫引導(dǎo)類與測試
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
}
啟動服務(wù)
打印日志對象 Logger

可以在控制臺看到如下日志
printAllLogger begin>>>>>>>>
ROOT
com.olive.Application
com.olive.controller.LoggerController
// 省略一萬條記錄
printAllLogger end>>>>>>>>
打印各日志級別的日志
目前 logback-spring.xml 配置的 ROOT 的日志級別是 info 級別

可以看到控制臺只打印 info 級別及 info 級別以上的日志
2021-05-12 22:10:27.959 [http-nio-8080-exec-3] INFO com.olive.controller.LoggerController - loggerPrint info>>>>
2021-05-12 22:10:27.959 [http-nio-8080-exec-3] WARN com.olive.controller.LoggerController - loggerPrint warn>>>>
2021-05-12 22:10:27.960 [http-nio-8080-exec-3] ERROR com.olive.controller.LoggerController - loggerPrint error>>>>
設(shè)置 ROOT 日志對象的日志級別

調(diào)用完以上接口后,再次調(diào)用 http://127.0.0.1:8080/logger/print 接口??梢钥吹娇刂婆_

打印了大量 debug 級別及 debug 級別以上的日志

喜歡,在看
