1. 概述
在本教程中,我們將探索 Spring Boot 中可用的主要日誌選項。
有關 Logback 的更詳細信息,請參閲《Logback 指南》,而 Log4j2 的介紹則在《Log4j2 – Appenders、佈局和過濾器》中。
2. 初始設置
首先,讓我們創建一個 Spring Boot 模塊。推薦的方法是使用 Spring Initializr,正如我們在 Spring Boot 教程中所介紹的。
現在,讓我們創建一個唯一的類文件,LoggingController:
@RestController
public class LoggingController {
Logger logger = LoggerFactory.getLogger(LoggingController.class);
@RequestMapping("/")
public String index() {
logger.trace("A TRACE Message");
logger.debug("A DEBUG Message");
logger.info("An INFO Message");
logger.warn("A WARN Message");
logger.error("An ERROR Message");
return "Howdy! Check out the Logs to see the output...";
}
}
在加載 Web 應用程序後,只需訪問 http://localhost:8080/,即可觸發這些日誌行。
3. 無配置日誌
Spring Boot 是一個非常實用的框架。它允許我們忘記大部分的配置設置,其中許多配置設置是它帶有偏見的自動調整。
在日誌方面,唯一的強制依賴是 Apache Commons Logging。
我們只需要在使用 Spring 4.x 時導入它 (Spring Boot 1.x),因為在 Spring 5 中,它由 Spring Framework 的 spring-jcl 模塊提供 (Spring Boot 2.x)。
如果使用 Spring Boot Starter,我們完全不必擔心導入 spring-jcl (而我們幾乎總是這樣做的)。這是因為每個 Starter,比如我們的 spring-boot-starter-web,都依賴於 spring-boot-starter-logging,它已經替我們導入了 spring-jcl。
3.1. 默認 Logback 日誌記錄
使用啓動器時,Logback 默認用於日誌記錄。
Spring Boot 預配置了其模式和 ANSI 顏色,以提高標準輸出的可讀性。
現在讓我們運行應用程序並訪問 http://localhost:8080/ 頁面,並查看控制枱中的情況:
正如我們所看到的,Logger 的默認日誌級別已設置為 INFO,這意味着 TRACE 和 DEBUG 消息不可見。
為了在不修改配置的情況下激活它們,我們可以通過命令行傳遞 –debug 或 –trace 參數:
java -jar target/spring-boot-logging-0.0.1-SNAPSHOT.jar --trace
3.2. 日誌級別 (Log Levels)
Spring Boot 也通過環境變量提供更精細的日誌級別設置。有多種方法可以實現這一點。
首先,我們可以將日誌級別設置在 VM 選項中:
-Dlogging.level.org.springframework=TRACE
-Dlogging.level.com.baeldung=TRACE如果使用 Maven,我們也可以通過命令行定義我們的日誌設置:
mvn spring-boot:run
-Dspring-boot.run.arguments=--logging.level.org.springframework=TRACE,--logging.level.com.baeldung=TRACE在使用 Gradle 時,我們可以通過命令行傳遞日誌設置。 這將需要設置 bootRun 任務。
完成這些步驟後,我們運行應用程序:
./gradlew bootRun -Pargs=--logging.level.org.springframework=TRACE,--logging.level.com.baeldung=TRACE如果想要永久更改日誌的詳細程度,可以在 application.properties文件中,如文檔中所述:此處:
logging.level.root=WARN
logging.level.com.baeldung=TRACE
最後,我們可以通過使用我們的日誌框架配置文件的方式,永久地更改日誌級別。
我們提到 Spring Boot Starter 默認使用 Logback。下面我們來看如何定義一個 Logback 配置文件的片段,其中設置了兩個不同包的級別:
<logger name="org.springframework" level="INFO" />
<logger name="com.baeldung" level="INFO" />請記住,如果某個包的日誌級別使用上述的不同選項定義了多次,但使用了不同的日誌級別,則將使用最低級別的日誌級別。
因此,如果在同一時間使用Logback、Spring Boot和環境變量設置日誌級別時,日誌級別將是 TRACE,因為它是在請求級別中最低的級別。
3.3. 默認日誌文件
默認情況下,Spring Boot 將消息記錄到控制枱。但是,它也允許將日誌寫入文件,同時保留控制枱輸出。我們可以使用 logging.file.name 或 logging.file.path 屬性來實現這一點。當同時設置這兩個屬性時,logging.file.name 將具有優先權,logging.file.path 將被忽略。
以下是在 application.properties 文件中的示例配置:
logging.file.name=logs/app.log
logging.file.path=logslogging.file.name 屬性指定了完整的路徑,包括目錄和文件名。如果指定的該文件不存在,Spring Boot 將會自動創建它。此外,文件路徑可以是絕對路徑或相對路徑。
此外,logging.file.path 屬性指定了用於存儲日誌文件的目錄。如果僅設置此屬性,Spring Boot 將自動為日誌文件生成默認文件名。 類似於logging.file.name 屬性,文件路徑可以是絕對路徑或相對路徑。
重要的是,在 Spring Boot 版本 2.3 之前,等效的屬性名為 logging.path 和 logging.name。
<h2><strong>4. Logback 配置日誌</strong></h2>
<p>即使默認配置也很有用(例如,在POC或快速實驗中以零時間開始),但它很可能不足以滿足我們的日常需求。</p>
<p>讓我們看看<strong>如何包含一個Logback配置</strong>,使用不同的顏色和日誌模式,併為<em>控制枱</em>和<em>文件</em>輸出指定不同的規範,以及具有合理的<em>滾動策略</em>,以避免生成巨大的日誌文件。</p>
<p>首先,我們應該找到一種解決方案,允許我們單獨處理日誌設置,而不是污染<em>application.properties</em>,該文件通常用於許多其他應用程序設置。</p>
<p><strong>當類路徑中的文件具有以下名稱時,Spring Boot 將自動加載</strong>它,覆蓋默認配置:</p>
<ul>
<li><em>logback-spring.xml</em></li>
<li><em>logback.xml</em></li>
<li><em>logback-spring.groovy</em></li>
<li><em>logback.groovy</em></li>
</ul>
<p><strong>Spring 建議儘可能使用<em>-spring</em>變體</strong>,如文檔<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#boot-features-custom-log-configuration">中所述</a>。</p>
<p>讓我們編寫一個簡單的<em>logback-spring.xml</em>:</p>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOGS" value="./logs" />
<appender name="Console"
class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1}): %msg%n%throwable
</Pattern>
</layout>
</appender>
<appender name="RollingFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS}/spring-boot-logger.log</file>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d %p %C{1} [%t] %m%n</Pattern>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily and when the file reaches 10 MegaBytes -->
<fileNamePattern>${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- LOG everything at INFO level -->
<root level="info">
<appender-ref ref="RollingFile" />
<appender-ref ref="Console" />
</root>
<!-- LOG "com.baeldung*" at TRACE level -->
<logger name="com.baeldung" level="trace" additivity="false">
<appender-ref ref="RollingFile" />
<appender-ref ref="Console" />
</logger>
</configuration>
運行應用程序時,輸出如下:
如您所見,現在記錄了 TRACE 和 DEBUG 消息,並且整體控制枱模式與之前不同,在文本和色彩上都不同。
它現在還在當前路徑下創建的 /logs 文件夾中記錄日誌,並採用滾動策略進行歸檔。
5. Log4j2 配置日誌記錄
雖然 Apache Commons Logging 是核心,Logback 是提供的參考實現,但所有指向其他日誌庫的配置都已經包含在內,方便切換。
為了使用除了 Logback 之外的任何日誌庫,我們需要從我們的依賴中排除它們。
對於像這個啓動器這樣的每個啓動器(目前只有一個,但我們可能有很多):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.5.7</version>
</dependency>
我們需要將其轉換為一個精簡版本,並且(僅一次)添加我們的替代庫,通過一個啓動器在這裏實現:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.5.7</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>3.5.7</version>
</dependency>
此時,我們需要將以下文件放置在 classpath 中:
- log4j2-spring.xml
- log4j2.xml
我們將通過 Log4j2 (覆蓋 SLF4J) 進行輸出,無需進行進一步修改。
讓我們編寫一個簡單的 log4j2-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1}}{bright,yellow}: %msg%n%throwable" />
</Console>
<RollingFile name="RollingFile"
fileName="./logs/spring-boot-logger-log4j2.log"
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
<PatternLayout>
<pattern>%d %p %C{1} [%t] %m%n</pattern>
</PatternLayout>
<Policies>
<!-- rollover on startup, daily and when the file reaches
10 MegaBytes -->
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy
size="10 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<!-- LOG everything at INFO level -->
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile" />
</Root>
<!-- LOG "com.baeldung*" at TRACE level -->
<Logger name="com.baeldung" level="trace"></Logger>
</Loggers>
</Configuration>
當我們運行應用程序時,輸出如下:
如你所見,輸出與 Logback 的輸出差異很大,這證明我們現在完全使用了 Log4j2。
除了 XML 配置之外,Log4j2 還允許我們使用 YAML 或 JSON 配置,詳情請參考 這裏。
6. 不使用 SLF4J 的 Log4j2
我們可以直接使用 Log4j2,無需通過 SLF4J。
為了實現這一點,我們只需使用原生類:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
// [...]
Logger logger = LogManager.getLogger(LoggingController.class);
我們不需要對標準的 Log4j2 Spring Boot 配置進行任何其他修改。
現在我們可以利用 Log4j2 的全新功能,而無需被舊的 SLF4J 接口所困擾。但我們也因此與該實現方案綁定,在切換到其他日誌框架時,我們需要重寫我們的代碼。
7. 使用 Lombok 進行日誌記錄
在我們之前看到的示例中,我們需要聲明一個日誌記錄器實例,來自我們的日誌記錄框架。
這部分樣板代碼可能會令人厭煩。我們可以使用 Lombok 引入的各種註解來避免它。
首先,我們需要在構建腳本中添加 Lombok 依賴才能使用它:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.42</version>
<scope>provided</scope>
</dependency>7.1. @Slf4j 和 @CommonsLog</h3
SLF4J 和 Apache Commons Logging API 允許我們無需影響代碼的情況下,靈活地更改日誌框架。
並且我們可以 使用 Lombok 的 @Slf4j 和 @CommonsLog 註解 將正確的日誌器實例添加到我們的類中:org.slf4j.Logger 用於 SLF4J,org.apache.commons.logging.Log 用於 Apache Commons Logging。
要查看這些註解在行動中的效果,讓我們創建一個類似於 LoggingController 的類,但沒有日誌器實例。 我們將其命名為 LombokLoggingController 並用 @Slf4j 註解標記它:
@RestController
@Slf4j
public class LombokLoggingController {
@RequestMapping("/lombok")
public String index() {
log.trace("A TRACE Message");
log.debug("A DEBUG Message");
log.info("An INFO Message");
log.warn("A WARN Message");
log.error("An ERROR Message");
return "Howdy! Check out the Logs to see the output...";
}
}請注意,我們對片段進行了輕微調整,使用 log 作為我們的logger實例。這是因為添加 @Slf4j 註解會自動添加名為 log 的字段。
通過 零配置日誌,應用程序將使用底層日誌實現 Logback 進行日誌記錄。同樣,Log4j2 實現也用於與 Log4j2-Configuration Logging 配合使用進行日誌記錄。
當我們用 @CommonsLog 替換 @Slf4j 註解時,我們也能獲得相同的行為。
7.2. @Log4j2
我們可以使用註解 @Log4j2 直接使用 Log4j2。因此,我們修改了 LombokLoggingController,使用 @Log4j2 代替 @Slf4j 或 @CommonsLog:
@RestController
@Log4j2
public class LombokLoggingController {
@RequestMapping("/lombok")
public String index() {
log.trace("A TRACE Message");
log.debug("A DEBUG Message");
log.info("An INFO Message");
log.warn("A WARN Message");
log.error("An ERROR Message");
return "Howdy! Check out the Logs to see the output...";
}
}
除了日誌記錄之外,Lombok 還提供其他註解,以幫助我們保持代碼的整潔和有序。有關更多信息,請參閲《Lombok 項目介紹》,我們還提供關於使用 Eclipse 和 IntelliJ 設置 Lombok 的教程。
8. 謹防使用 Java Util Logging
Spring Boot 也支持 JDK 日誌,通過 logging.properties 配置文件的支持。
儘管如此,在某些情況下,不建議使用它。如 文檔所述:
Java Util Logging 存在已知的問題,會導致在“可執行 jar”中運行時出現問題。因此,如果可能,我們建議避免在“可執行 jar”中運行時。
此外,在 Spring 4 中手動排除 commons-logging 在 pom.xml 中,以避免日誌庫之間的潛在衝突,也是一個好習慣。Spring 5 則自動處理,因此在使用 Spring Boot 2 時,我們無需進行任何操作。
9. Windows 上的 JANSI
雖然基於 Unix 的操作系統,如 Linux 和 Mac OS X,默認支持 ANSI 顏色代碼,但在 Windows 命令行中,一切都將是單色的。
Windows 可以通過名為 JANSI 的庫獲取 ANSI 顏色。
我們應該注意潛在的類加載問題。
必須導入並明確在配置中激活它,如下所示:
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<!-- more stuff -->
</configuration>
ANSI 轉義序列在許多平台上原生支持,但在 Windows 上默認不支持。為了啓用 ANSI 支持,請將 Jansi JAR 包添加到我們的應用程序中,並將屬性 log4j.skipJansi 設置為 false。這允許 Log4j 使用 Jansi 添加 ANSI 轉義碼,以便在向控制枱寫入時使用。
注意:在 Log4j 2.10 之前,Jansi 默認啓用。由於 Jansi 需要本機代碼,因此 Jansi 只能被單個類加載器加載。對於 Web 應用程序,這意味着 Jansi JAR 包必須位於 Web 容器的類路徑中。為了避免 Web 應用程序出現問題,Log4j 不再在 Log4j 2.10 及更高版本中嘗試在沒有 Log4j 顯式配置的情況下加載 Jansi。
此外,還值得注意的是:
- 佈局 文檔頁面包含有用的 Log4j2 JANSI 信息,在 highlight{pattern}{style} 部分。
- 雖然 JANSI 可以着色輸出,但 Spring Boot 的 Banner(原生或通過 banner.txt 文件自定義)將保持單色。
10. 結論
我們已經瞭解瞭如何在 Spring Boot 項目中與主要日誌框架進行交互的主要方法。
我們還探討了每種解決方案的主要優勢和潛在問題。