Java 應用程式透過 SLF4J 統一介面將日誌傳送到 Log4j2 主控台與檔案的流程

SLF4J 2+Log4j2 教學:Maven 依賴、設定與 Java 範例

Java 專案常同時使用不同函式庫,而每個函式庫可能採用不同的日誌系統。SLF4J(Simple Logging Facade for Java)的用途,就是讓程式碼依賴一套統一的日誌 API,再由應用程式選擇 Log4j2、Logback 或 java.util.logging 等後端。本文保留原文「統一介面、降低切換成本」的核心,並更新成 SLF4J 2 與 Log4j2 的現行配置。

先看結論:函式庫通常只依賴 slf4j-api;應用程式除了 API,還要在執行階段提供一個 Provider。若選擇 Log4j2,SLF4J 2 應搭配 log4j-core 與 log4j-slf4j2-impl,不要沿用舊文的 log4j-slf4j-impl。

SLF4J 是什麼?

SLF4J 是日誌門面(facade),提供 Logger、LoggerFactory 與常用的 debug()、info()、warn()、error() 等 API。商業邏輯只需要面向 SLF4J 寫程式,不必直接綁定特定日誌實作。

SLF4J 本身不是完整的日誌儲存與輸出系統。真正決定日誌格式、等級、檔案輪替與輸出目的地的,是 Log4j2、Logback 或 JUL 等後端。

API、Provider 與日誌實作有什麼差別?

  • API:程式碼直接呼叫的介面,例如 slf4j-api。
  • Provider:把 SLF4J 呼叫交給實際後端的連接層。SLF4J 2 使用 Java ServiceLoader 尋找 Provider。
  • 日誌實作:真正處理與輸出日誌,例如 Log4j Core、Logback 或 JUL。

這樣的分層讓函式庫不必替使用者決定後端;最終應用程式則可以依部署環境選擇一套實作。

函式庫與應用程式的依賴原則

如果你正在開發可被其他專案引用的函式庫,正式依賴通常只放 slf4j-api,日誌實作只在測試範圍使用。若把 Log4j Core 或 Logback 強制帶進函式庫,可能與使用者應用程式原本的後端衝突。

如果你正在開發可執行應用程式,則需要選定一個後端。下面示範 SLF4J 2 搭配 Log4j2。

Maven:SLF4J 2 搭配 Log4j2

以下版本是撰文時官方文件所列的穩定版本。正式導入前仍應查看官方下載頁與相依套件掃描結果。Log4j 模組使用 BOM 管理,可避免 Core 與橋接器版本不一致。

<properties>
    <slf4j.version>2.0.18</slf4j.version>
    <log4j2.version>2.26.1</log4j2.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-bom</artifactId>
            <version>${log4j2.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

log4j-slf4j2-impl 是提供給 SLF4J 2 的橋接器;舊的 log4j-slf4j-impl 適用於 SLF4J 1.7 及更早版本。若專案仍停留在 SLF4J 1.7,應先盤點相依套件,再整體升級,不要只替換單一 JAR。

設定 log4j2.xml

在 src/main/resources/log4j2.xml 建立設定檔。以下範例把 INFO 以上日誌輸出到主控台:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout
                pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

開發環境可使用容易閱讀的 PatternLayout;正式環境若要送進集中式日誌平台,Apache Log4j 官方建議評估結構化 JSON 輸出,以便欄位查詢與後續分析。

Java 類別中如何使用 SLF4J?

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OrderService {
    private static final Logger LOGGER =
        LoggerFactory.getLogger(OrderService.class);

    public void process(String orderId) {
        LOGGER.debug("Starting order id={}", orderId);

        try {
            // 執行訂單流程
            LOGGER.info("Order completed id={}", orderId);
        } catch (RuntimeException ex) {
            LOGGER.error("Order failed id={}", orderId, ex);
            throw ex;
        }
    }
}

使用 {} 參數化日誌,可以避免先以字串串接產生不必要物件,也能讓例外物件保留完整 stack trace。不要把密碼、Token、信用卡號或個人資料寫入日誌。

切換日誌後端時,哪些程式碼不需要改?

只要商業程式碼依賴 SLF4J API,從 Log4j2 改成 Logback 或 JUL 時,通常不需要改動 Logger 呼叫。要更換的是 classpath 上的 Provider/後端與設定檔,完成後重新啟動應用程式。

這不是在同一個執行中的 JVM 任意熱切換後端。原文所說的「執行時切換」容易誤解,較準確的說法是:SLF4J 讓部署組態可以替換後端,而應用程式碼維持不變。

常見錯誤與排查

No SLF4J providers were found

SLF4J 2 找不到 Provider 時會顯示警告。確認執行階段是否真的包含 log4j-slf4j2-impl、Logback Provider 或其他相容後端,而不只是 slf4j-api。

Class path contains multiple SLF4J providers

同時帶入 Logback、Log4j2 橋接器或 slf4j-simple,可能造成多 Provider 警告與不可預期選擇。可使用 mvn dependency:tree 找出傳遞依賴,最後只保留一套後端。

不要同時建立循環橋接

若已用 log4j-slf4j2-impl 把 SLF4J 送進 Log4j2,就不要再加入把 Log4j API 送回 SLF4J 的 log4j-to-slf4j,否則會形成循環。

SLF4J 1.7 與 2.x 混用

SLF4J 2 改用 ServiceLoader 尋找 Provider。若 API 與 Provider 的主版本不匹配,可能出現找不到 Provider、忽略舊 binding 或類別載入錯誤。升級時應一起檢查 API、後端、橋接器與框架版本。

Spring Boot 專案怎麼處理?

Spring Boot 預設已有日誌方案,不應照一般 Maven 範例重複加入整套依賴。若確定要改用 Log4j2,使用官方的 spring-boot-starter-log4j2,並依 Spring Boot 文件排除預設 logging starter。先用相依樹確認沒有同時保留兩套後端。

重點整理

  • SLF4J 是統一 API,不是完整日誌後端。
  • 函式庫通常只依賴 API;應用程式負責選擇一個 Provider 與實作。
  • SLF4J 2 搭配 Log4j2 應使用 log4j-slf4j2-impl。
  • 透過 BOM 保持 Log4j 模組版本一致,並避免多 Provider 或循環橋接。
  • 使用參數化日誌,保留例外 stack trace,也不要記錄敏感資料。

相關教學與官方資料

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *