Spring Boot 日誌框架的使用替換與剖析

注意:本 Spring Boot 系列文章基於 Spring Boot 版本 v2.1.1.RELEASE

進行學習分析,版本不同可能會有細微差別。

前言

Spring Boot 日誌框架的使用替換與剖析

Spring 框架選擇使用了 JCL 作為默認日誌輸出。而 Spring Boot 默認選擇了 SLF4J 結合 LogBack。那我們在項目中該使用哪種日誌框架呢?在對於不同的第三方 jar 使用了不同的日誌框架的時候,我們該怎麼處理呢?

1. 日誌框架介紹

日誌對於應用程序的重要性不言而喻,不管是記錄運行情況還是追蹤線上問題,都離不開對日誌的分析,在 Java 領域裡存在著多種日誌框架,如 JUL, Log4j, Log4j2, Commons Loggin, Slf4j, Logback 等。關於 Log4j, Log4j2 和 Slf4j 直接的故事這裡不做介紹,有興趣可以自行百度。

2. SLF4 的使用

在開發的時候不應該直接使用日誌實現類,應該使用日誌的抽象層。具體參考 SLF4J 官方。

下圖是 SLF4J 結合各種日誌框架的官方示例,從圖中可以清晰的看出 SLF4J API 永遠作為日誌的門面,直接應用與應用程序中。

Spring Boot 日誌框架的使用替換與剖析

SLF4

同時 SLF4 官方給出了簡單示例。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}

需要注意的是,要為系統導入 SLF4J 的 jar 和 日誌框架的實現 jar. 由於每一個日誌的實現框架都有自己的配置文件,所以在使用 SLF4 之後,配置文件還是要使用實現日誌框架的配置文件。

3. 統一日誌框架的使用

一般情況下,在項目中存在著各種不同的第三方 jar ,且它們的日誌選擇也可能不盡相同,顯然這樣是不利於我們使用的,那麼如果我們想為項目設置統一的日誌框架該怎麼辦呢?

在 SLF4J 官方,也給了我們參考的例子

Spring Boot 日誌框架的使用替換與剖析

從圖中我們得到一種統一日誌框架使用的方式,可以使用一種和要替換的日誌框架類完全一樣的 jar 進行替換,這樣不至於原來的第三方 jar 報錯,而這個替換的 jar 其實使用了 SLF4J API. 這樣項目中的日誌就都可以通過 SLF4J API 結合自己選擇的框架進行日誌輸出。

統一日誌框架使用步驟歸納如下:

  1. 排除系統中的其他日誌框架。
  2. 使用中間包替換要替換的日誌框架。
  3. 導入我們選擇的 SLF4J 實現。

4. Spring Boot 的日誌關係

4.1. 排除其他日誌框架

根據上面總結的要統一日誌框架的使用,第一步要排除其他的日誌框架,在 Spring Boot 的 Maven 依賴裡可以清楚的看到 Spring Boot 排除了其他日誌框架。

Spring Boot 日誌框架的使用替換與剖析

Spring Boot 排除其他日誌框架

我們自行排除依賴時也只需要按照圖中的方式就好了。

4.2. 統一框架引入替換包

其實 Spring Boot 也是使用了 SLF4J+logback 的日誌框架組合,查看 Spring Boot 項目的 Maven 依賴關係可以看到 Spring Boot 的核心啟動器 spring-boot-starter 引入了 spring-boot-starter-logging.

 <dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-logging/<artifactid>
<version>2.1.1.RELEASE/<version>
<scope>compile/<scope>
/<dependency>

而 spring-boot-starter-logging 的 Maven 依賴主要引入了 logback-classic (包含了日誌框架 Logback 的實現),log4j-to-slf4j (在 log4j 日誌框架作者開發此框架的時候還沒有想到使用日誌抽象層進行開發,因此出現了 log4j 向 slf4j 轉換的工具),jul-to-slf4j ( Java 自帶的日誌框架轉換為 slf4j).

 <dependencies>
<dependency>
<groupid>ch.qos.logback/<groupid>
<artifactid>logback-classic/<artifactid>
<version>1.2.3/<version>
<scope>compile/<scope>
/<dependency>
<dependency>
<groupid>org.apache.logging.log4j/<groupid>
<artifactid>log4j-to-slf4j/<artifactid>
<version>2.11.1/<version>
<scope>compile/<scope>
/<dependency>

<dependency>
<groupid>org.slf4j/<groupid>
<artifactid>jul-to-slf4j/<artifactid>
<version>1.7.25/<version>
<scope>compile/<scope>
/<dependency>
/<dependencies>

從上面的分析,Spring Boot 對日誌框架的使用已經是清晰明瞭了,我們使用 IDEA 工具查看 Maven 依賴關係,可以清晰的看到日誌框架的引用。如果沒有 IDEA 工具,也可以使用 Maven 命令查看依賴關係。

mvn dependency:tree
Spring Boot 日誌框架的使用替換與剖析

Spring Boot Maven 依賴

由此可見,Spring Boot 可以自動的適配日誌框架,而且底層使用 SLF4 + LogBack 記錄日誌,如果我們自行引入其他框架,需要排除其日誌框架。

5. Spring Boot 的日誌使用

5.1. 日誌級別和格式

從上面的分析,發現 Spring Boot 默認已經使用了 SLF4J + LogBack . 所以我們在不進行任何額外操作的情況下就可以使用 SLF4J + Logback 進行日誌輸出。

編寫 Java 測試類進行測試。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
*


* 測試日誌輸出,
* SLF4J 日誌級別從小到大trace,debug,info,warn,error
*
* @Author niujinpeng
* @Date 2018/12/11 21:12


*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class LogbackTest {
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void testLog() {
logger.trace("Trace 日誌...");
logger.debug("Debug 日誌...");
logger.info("Info 日誌...");
logger.warn("Warn 日誌...");
logger.error("Error 日誌...");
}
}

已知日誌級別從小到大為 trace < debug < info < warn < error . 運行得到輸出如下。由此可見 Spring Boot 默認日誌級別為 INFO .

2018-12-11 23:02:58.028 [main] INFO n.c.boot.LogbackTest - Info 日誌...
2018-12-11 23:02:58.029 [main] WARN n.c.boot.LogbackTest - Warn 日誌...
2018-12-11 23:02:58.029 [main] ERROR n.c.boot.LogbackTest - Error 日誌...

從上面的日誌結合 Logback 日誌格式可以知道 Spring Boot 默認日誌格式是。

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
# %d{yyyy-MM-dd HH:mm:ss.SSS} 時間
# %thread 線程名稱
# %-5level 日誌級別從左顯示5個字符寬度
# %logger{50} 類名
# %msg%n 日誌信息加換行

至於為什麼 Spring Boot 的默認日誌輸出格式是這樣?

Spring Boot 日誌框架的使用替換與剖析

Spring Boot 默認日誌輸出

我們可以在 Spring Boot 的源碼裡找到答案。

5.2 自定義日誌輸出

可以直接在配置文件編寫日誌相關配置。

# 日誌配置
# 指定具體包的日誌級別
logging.level.net.codingme=debug

# 控制檯和日誌文件輸出格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
# 日誌文件大小
logging.file.max-size=10MB
# 保留的日誌時間
logging.file.max-history=10
# 日誌輸出路徑,默認文件spring.log
logging.path=systemlog
#logging.file=log.log

關於日誌的輸出路徑,可以使用 logging.file 或者 logging.path 進行定義,兩者存在關係如下表。

logging.file logging.path 例子描述(沒有) (沒有) 僅控制檯記錄。具體文件(沒有) my.log 寫入指定的日誌文件,名稱可以是精確位置或相對於當前目錄。(沒有) 具體目錄/var/log 寫入 spring.log 指定的目錄,名稱可以是精確位置或相對於當前目錄。

6. 替換日誌框架

因為 Log4j 日誌框架已經年久失修,原作者都覺得寫的不好,所以下面演示替換日誌框架為 Log4j2 的方式。根據官網我們 Log4j2 與 logging 需要二選一,因此修改 pom如下。

 <dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-web/<artifactid>
<exclusions>
<exclusion>
<artifactid>spring-boot-starter-logging/<artifactid>
<groupid>org.springframework.boot/<groupid>
/<exclusion>
/<exclusions>
/<dependency>
<dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-log4j2/<artifactid>
/<dependency>


分享到:


相關文章: