(11) Spring Boot 使用 Logback 或 Log4j2

Albert Hg
learning-from-jhipster
11 min readOct 29, 2020

本篇文章將會介紹如何在 Spring Boot 中使用 Logback 以及 Log4j2,但由於這兩個是不同的 Logging Framework,所以在最後我們只會選擇其中一個作為本系列文的專案中的 Logging Framework。

本系列文的 Spring Boot 是使用 2.3.1 的版本,而在這個版本中預設使用的 Logging Framework 是 Logback,所以在一開始會介紹如何使用 Logback 進行設定檔的配置,接著才會介紹 Log4j2 並將其加入我們的專案中。

通用配置

Spring Boot - Common Application properties 內有許多常見的通用設定,在 Core properties 的部分可以找到 Logging 相關的通用設定。

這裡我將相關的 Logging 配置改為使用 yml 的格式撰寫,並且加上了一些說明:

https://gist.github.com/albert-hg/7211f3373ada87a17f501c63a845d6bb

可以看到,如果你想要使用properties設定的話,那麼其實可以設定的參數是非常限定的,當然其中還是有一些比較通用的像是「logging.level.*」,其餘更多的設定建議是直接額外寫在對應的 Logging Framework 的設定檔中。

而 Logging Framework 的設定檔會大多是以 xml 的格式來撰寫,至於要讓 Spring Boot 可以讀取設定檔的預設路徑則是為「\src\main\resources」底下,其命名格式會依照使用不同的 Logging Framework 而定(來源:Spring Boot — Custom Log Configuration):

  • Logback: 「logback-spring.xml」、「logback-spring.groovy」、「logback.xml」、「logback.groovy」
  • Log4j2: 「log4j2-spring.xml」、「log4j2.xml」
  • Java Util Logging: 「logging.properties」

因為我們是使用 Spring Boot 作為專案開發的框架,因此習慣上我們會選擇帶有 「*-spring.xml」的命名方式,作為 Logback 與 Log4j2 的配置名稱。

加入 logback-spring.xml 配置

一個常見的配置大概會像這樣:

https://gist.github.com/albert-hg/889c8c60ee748c841710cf287a23cf7a

那麼就可以在 Console 的部分看到印出 Log 的格式是依照 name=CONSOLE 的 <appender>所設定的 <pattern> 印出:

而在輸出在 File 部分的 Log 的格式則是依照 name=FILE 的 <appender>所設定的 <pattern> 輸出於指定路徑的 Log File 上:

這裡比較值得一提的是,我們有需要引用 Spring Boot 對於 Logback 的預設配置嗎?

其實這就不一定了,我們可以先來看看這個預設配置 到底做了些甚麼事情:

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml

原來這裡面其實也已經有包含 CONSOLE 與 FILE 兩個 Appender,所以如果沒有想要特別的需求要客製化 Log 輸出的格式或路徑格式,那麼使用預設配置就可以了,但如果你要比較有彈性的去編輯你的配置,那麼還是建議就自己寫一份吧!

其他相關的配置說明可以參考:

  1. Pattern 的設定:
    - http://logback.qos.ch/manual/encoders.html
    - http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout
  2. Logging in Spring Boot
    - https://www.baeldung.com/spring-boot-logging
    - https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-logging

使用 Log4j2

在開始配置 log4j2-spring.xml 之前,我們必須先停止使用 Logback 才行。因此我們必須修改 pom.xml 的 dependency。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

排除預設的 logging starter 後,再將 log4j2 導入,並進行文件配置的部分。

有兩種方式可以將 log4j2 導入專案:

1. 偷懶使用 Spring Boot 的 log4j2 的 Starter

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

雖然是偷懶,但總歸還是要知道實際上發生了甚麼事情阿!(所以請繼續往下看第 2 點的說明)

2. 當個乖乖牌自己加入相關的 dependency

還記得這張圖嗎?

由於 Spring Boot 預設使用 Slf4j 作為 Logging 的 API Interface,所以我們要想辦法連連看,要把 Slf4j 連到 Log4j-core 的位置。非常明顯的,我們需要加入的 Dependency 就是 「log4j-slf4j-impl」,另外還要加入輸出 Log 的框架:「Log4j-core」。

在上一篇文章中也有提到:

Spring Boot 在開發的部分,都是使用 JCL 的 Interface 來記錄 Log

而在輸出 Log 的部分則是使用 JUL,所以必須將 JUL 連到 Log4j-core,可是因為 Spring Boot 預設還是使用 Slf4j 的 API Interface,要讓 Slf4j 攔截 JUL 的輸出,則會需要「jul-to-slf4j」而不是「log4j-jul」(所以不要走錯路了!)。

還有,假設你不想使用 Logback 的 API Interface,而想要使用 Log4j2 的 API Interface,那麼你還必須要再加入 Log4j-api。

我們把關係圖再畫一下:

如此我們只要加入如下四個 Dependency 就可以了:

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>

加入 log4j2-spring.xml 配置

log4j2-spring.xml 是 Spring Boot 會吃的一個預設載入配置的檔案名稱,這裡有一個地方必須特別注意:

log4j2 沒有辦法在一個配置檔案中,同時對不同的執行環境進行對應的配置設定。

如果你的專案不需要對不同執行環境(例如dev或prod)進行 Log 的輸出配置,那麼你就可以很放心地用 log4j2-spring.xml 作為你的 Logging 配置。

但如果你需要依照不同的執行環境進行不同的 Log 輸出配置,那麼就「不能用」log4j2-spring.xml 作為你 Logging 配置檔案的名稱。

若先單純不考慮是否要因為不同執行環境而有不同配置的形況下,那麼一個常見的配置大概會像這樣:

https://gist.github.com/albert-hg/889c8c60ee748c841710cf287a23cf7a

但如果你想要依照不同環境使用不同的 Logging 配置,那麼就必須避免 Spring Boot 對 log4j2 的配置檔的預設名稱,包含「log4j2-spring.xml」、「log4j2.xml」。

同時你也必須在對應的 Spring Boot 配置檔(application-*.yml)中指定不同環境所對應的 log4j2 的配置路徑為何,像是:

https://gist.github.com/albert-hg/713956982fb97962f84a78c48eb5f410

這麼一來,你就可以依照指定的不同環境使用不同的 Logging 配置檔了。

更多關於 Log4j2 的說明也可以直接參考:

  1. Log4j2 Manual Configuration
    https://logging.apache.org/log4j/2.x/manual/configuration.html

文末

不論是 Logback 或 Log4j2 的 Logging Framework 都很不錯,但其實對於 Spring Boot 來說,Logback 的整合性會比較高一點,而且 Logback 是可以直接吃到 Spring Boot 的相關參數,但 Log4j2 的話在這一方面就相對缺失了。

本篇文章一開始先討論了 Logback 的配置方式,最後又使用了 Log4j2 來討論如何將其加入 Spring Boot 的專案內。而這篇文章的範例程式碼將會停留在 Log4j2 的部分以供參考,但在下一篇文章開始,我就會再回歸 Logback 的懷抱了XD。

如果你是從建立 Spring Boot 專案開始實作到這邊,不曉得你有沒有覺得一件事情很麻煩,那就是「每次修改程式碼後都要手動停掉服務,然後再重新啟動一次」。

所以下一篇文章將會介紹如何可以在你每次更新你的程式碼時,讓正在執行的環境自動重新啟動,如此你就不用一直重複重新啟動的這個動作了~!

--

--

Albert Hg
learning-from-jhipster

I am a programmer but love other things. I am a nobody but keep myself going. I am a person who wishes to reach the heaven but lost the wings.