日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Boot 2动态修改日志级别

發布時間:2025/3/21 javascript 195 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 2动态修改日志级别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文基于:Spring Boot 2.1.3,理論支持Spring Boot 2.x所有版本。

作為程序猿,定位問題是我們的日常工作,而日志是我們定位問題非常重要的依據。傳統方式定位問題時,往往是如下步驟:

?將日志級別設低,例如?DEBUG?;?重啟應用;?復現問題,觀察日志;

如果能動態修改日志級別(無需重啟應用,就能立刻刷新),那絕對?如貓添翼?。事實上,從?Spring Boot 1.5?開始,Spring Boot Actuator?組件就已提供動態修改日志級別的能力。

TIPS

?其實更低版本也只需簡單擴展,即可實現動態修改日志級別。?對Spring Boot Actuator感到陌生的童鞋,可先前往?Spring Boot Actuator[1]?了解基礎用法。

廢話不多說了,亮代碼吧。

編碼

1 加依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>

這里的?spring-boot-starter-web?不是必須的,只是下面測試代碼要用到。

2 寫代碼

package com.itmuch.logging;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;/*** @author itmuch.com*/ @RestController public class TestController {private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);@GetMapping("/test")public String simple() {LOGGER.debug("這是一個debug日志...");return "test";} }

???????

3 寫配置:

management:endpoints:web:exposure:include: 'loggers'

???????由于Spring Boot 2.x默認只暴露?/health?以及?/info?端點,而日志控制需要用到?/loggers?端點,故而需要設置將其暴露。

代碼編寫完成啦。

測試

/loggers?端點提供了?查看?以及?修改?日志級別的能力。

測試1:查看當前應用各包/類的日志級別

訪問?http://localhost:8080/actuator/loggers?,可看到類似如下的結果:

{"levels": ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"],"loggers": {"ROOT": {"configuredLevel": "INFO","effectiveLevel": "INFO"}, "com.itmuch.logging.TestController": {"configuredLevel": null,"effectiveLevel": "INFO"}}// ...省略 }

???????測試2:查看指定包/類日志詳情

訪問?http://localhost:8080/actuator/loggers/com.itmuch.logging.TestController?,可看到類似如下的結果:

{"configuredLevel":null,"effectiveLevel":"INFO"}

由測試不難發現,想看哪個包/類的日志,只需構造?/actuator/loggers/包名類名全路徑?去訪問即可。

測試3:修改日志級別

在?TestController?類中,筆者編寫設置了一條日志?LOGGER.debug("這是一個debug日志...");?,而由測試1,默認的日志級別是INFO,所以不會打印。下面來嘗試將該類的日志級別設為DEBUG。

curl -X POST http://localhost:8080/actuator/loggers/com.itmuch.logging.TestController \ -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8" \ --data '{"configuredLevel":"debug"}'

???????如上,只需發送一個POST請求,并將請求body設為:{"configuredLevel":"debug"}?即可。

此時,訪問?localhost:8080/test?會看到類似如下的日志:

2019-03-28 16:24:04.513 DEBUG 19635 --- [nio-8080-exec-7] com.itmuch.logging.TestController : 這是一個debug日志...

并且,此時再訪問?http://localhost:8080/actuator/loggers/com.itmuch.logging.TestController?,可看到類似如下的結果:

{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}

說明已成功動態修改日志級別。

原理分析

TIPS

本節著重分析如何實現動態修改。

Actuator有約定,?/actuator/xxx?端點的定義代碼在?xxxEndpoint?中。故而,找到類?org.springframework.boot.actuate.logging.LoggersEndpoint?,可看到類似如下的代碼:

@Endpoint(id = "loggers") public class LoggersEndpoint {private final LoggingSystem loggingSystem;@WriteOperationpublic void configureLogLevel(@Selector String name,@Nullable LogLevel configuredLevel) {Assert.notNull(name, "Name must not be empty");this.loggingSystem.setLogLevel(name, configuredLevel);}// ...其他省略 }

???????其中,?Endpoint?、WriteOperation?、@Selector?都是Spring Boot 2.0開始提供的新注解。

@Endpoint(id = "loggers")?用來描述Spring Boot Actuator?的端點,這樣就會產生一個/actuator/loggers?的路徑,它類似于Spring MVC的?@RequestMapping("loggers")?。

@WriteOperation?表示這是一個寫操作,它類似于Spring MVC的?@PostMapping?。Spring Boot Actuator還提供了其他操作,如下表:

OperationHTTP method
@ReadOperationGET
@WriteOperationPOST
@DeleteOperationDELETE

@Selector?用于篩選?@Endpoint?注解返回值的子集,它類似于Spring MVC的?@PathVariable?。

這樣,上面的代碼就很好理解了——?configureLogLevel?方法里面就一行代碼 :this.loggingSystem.setLogLevel(name, configuredLevel);?,發送POST請求后,name就是我們傳的包名或者類名,configuredLevel就是我們傳的消息體。

怎么實現動態修改的呢?不妨點進去看看,然后發現代碼如下:

// org.springframework.boot.logging.LoggingSystem#setLogLevel public void setLogLevel(String loggerName, LogLevel level) {throw new UnsupportedOperationException("Unable to set log level"); }

???????嘿嘿,沒事,肯定有實現類, 該方法在如下實現類被實現:

# 適用于java.util.logging的LoggingSystem org.springframework.boot.logging.java.JavaLoggingSystem # 適用于Log4j 2的LoggingSystem org.springframework.boot.logging.log4j2.Log4J2LoggingSystem # 適用于logback的LoggingSystem org.springframework.boot.logging.logback.LogbackLoggingSystem # 啥都不干的LoggingSystem org.springframework.boot.logging.LoggingSystem.NoOpLoggingSystem

???????Spring Boot 2.x中,默認使用Logback,因此進入到?LogbackLoggingSystem?中,代碼如下:

@Overridepublic void setLogLevel(String loggerName, LogLevel level) {ch.qos.logback.classic.Logger logger = getLogger(loggerName);if (logger != null) {logger.setLevel(LEVELS.convertSystemToNative(level));}}

???????至此,就真相大白了。其實根本沒有黑科技,Spring Boot本質上還是使用了Logback的API,ch.qos.logback.classic.Logger.setLevel?實現日志級別的修改。

你可能會好奇

你可能會好奇,LoggingSystem有這么多實現類,Spring Boot怎么知道什么情況下用什么LoggingSystem呢?可在?org.springframework.boot.logging.LoggingSystem?找到類似如下代碼:

public abstract class LoggingSystem {private static final Map<String, String> SYSTEMS;static {Map<String, String> systems = new LinkedHashMap<>();systems.put("ch.qos.logback.core.Appender","org.springframework.boot.logging.logback.LogbackLoggingSystem");systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory","org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");systems.put("java.util.logging.LogManager","org.springframework.boot.logging.java.JavaLoggingSystem");SYSTEMS = Collections.unmodifiableMap(systems);}/*** Detect and return the logging system in use. Supports Logback and Java Logging.* @param classLoader the classloader* @return the logging system*/public static LoggingSystem get(ClassLoader classLoader) {String loggingSystem = System.getProperty(SYSTEM_PROPERTY);if (StringUtils.hasLength(loggingSystem)) {if (NONE.equals(loggingSystem)) {return new NoOpLoggingSystem();}return get(classLoader, loggingSystem);}return SYSTEMS.entrySet().stream().filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader)).map((entry) -> get(classLoader, entry.getValue())).findFirst().orElseThrow(() -> new IllegalStateException("No suitable logging system located"));}// 省略不相關內容... }

???????由代碼不難發現,其實就是構建了一個名為?SYSTEMS?的map,作為各種日志系統的字典;然后在?get?方法中,看應用是否加載了map中的類;如果加載了,就通過反射,初始化響應?LoggingSystem?。例如:Spring Boot發現當前應用加載了ch.qos.logback.core.Appender?,就去實例化?org.springframework.boot.logging.logback.LogbackLoggingSystem?。

界面

本文是使用?curl?手動發送?POST?請求手動修改日志級別的,該方式不適用生產,因為很麻煩,容易出錯。生產環境,建議根據Actuator提供的RESTful API定制界面,或使用?Spring Boot Admin?,可視化修改日志級別,如下圖所示:

想修改哪個包/類的日志級別,直接點擊即可。

配套代碼

  • GitHub[2]
  • Gitee[3]

總結

以上是生活随笔為你收集整理的Spring Boot 2动态修改日志级别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。