首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring Boot 整合 Log4j2 實現高效能非同步日誌系統

     編輯:Java 相關知識

為什麼選擇 Log4j2

Log4j 2.x 相較 1.x 具備顯著優勢:

  • 非同步記錄器:基於 LMAX Disruptor 無鎖環形緩衝區,吞吐量提升 10 倍以上
  • 無垃圾收集壓力:物件重用機制減少 GC
  • 豐富的配置能力:支援 XML/JSON/YAML/Properties,熱重載、腳本過濾
  • 模組化架構:API 與實現分離,便於遷移

Maven/Gradle 依賴配置

Gradle

dependencies {
    implementation "org.apache.logging.log4j:log4j-api:2.23.1"
    implementation "org.apache.logging.log4j:log4j-core:2.23.1"
    implementation "com.lmax:disruptor:3.4.4"  // 非同步支援
}

Maven

<dependencies>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.23.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.23.1</version>
    </dependency>
    <dependency>
        <groupId>com.lmax</groupId>
        <artifactId>disruptor</artifactId>
        <version>3.4.4</version>
    </dependency>
</dependencies>

log4j2.xml 進階配置解析

放置於 src/main/resources/log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF" monitorInterval="30">
    <!-- 變數定義 -->
    <Properties>
        <Property name="logPath">/var/log/myapp</Property>
        <Property name="logPattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} %L %M - %msg%xEx%n</Property>
        <Property name="consolePattern">%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
    </Properties>

    <Appenders>
        <!-- 控制台輸出 -->
        <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${consolePattern}"/>
        </Console>

        <!-- INFO/WARN 滾動檔案(按大小+時間) -->
        <RollingRandomAccessFile name="InfoFile" 
            fileName="${logPath}/app-info.log"
            filePattern="${logPath}/archive/%d{yyyy-MM}/app-info-%d{MM-dd-yyyy}-%i.log.gz"
            immediateFlush="false">
            <PatternLayout pattern="${logPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <DefaultRolloverStrategy max="30"/>
        </RollingRandomAccessFile>

        <!-- ERROR 獨立檔案 -->
        <RollingRandomAccessFile name="ErrorFile"
            fileName="${logPath}/app-error.log"
            filePattern="${logPath}/archive/%d{yyyy-MM}/app-error-%d{MM-dd-yyyy}-%i.log.gz"
            immediateFlush="false">
            <PatternLayout pattern="${logPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <DefaultRolloverStrategy max="30"/>
        </RollingRandomAccessFile>
    </Appenders>

    <Loggers>
        <!-- 根記錄器:非同步模式 -->
        <AsyncRoot level="INFO" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="InfoFile"/>
            <AppenderRef ref="ErrorFile"/>
        </AsyncRoot>

        <!-- 特定包別級別控制 -->
        <AsyncLogger name="com.myapp.dao" level="DEBUG" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="InfoFile"/>
            <AppenderRef ref="ErrorFile"/>
        </AsyncLogger>
    </Loggers>
</Configuration>

關鍵配置點解析

配置項說明
status="OFF"關閉 Log4j2 內部除錯輸出,生產環境建議 OFF 或 ERROR
monitorInterval="30"啟用熱重載,每 30 秒檢查配置變更
RollingRandomAccessFile高效能隨機存取檔案,配合 Disruptor 實現非同步寫入
immediateFlush="false"非同步模式下關閉立即刷新,由 Disruptor 批次寫入
AsyncRoot/AsyncLogger啟用非同步記錄器,**必須**有 Disruptor 依賴
additivity="false"禁止向父 Logger 傳遞,避免重複記錄

日誌工具類封裝

package com.myapp.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public final class L {
    private static final Logger LOG = LogManager.getLogger();
    private L() { throw new UnsupportedOperationException(); }

    public static Logger getLogger() { return LOG; }

    public static void trace(String msg) { LOG.trace(msg); }
    public static void debug(String msg) { LOG.debug(msg); }
    public static void info(String msg) { LOG.info(msg); }
    public static void warn(String msg) { LOG.warn(msg); }
    public static void error(String msg) { LOG.error(msg); }
    public static void error(String msg, Throwable t) { LOG.error(msg, t); }
    
    // 支援佔位符
    public static void info(String fmt, Object... args) { LOG.info(fmt, args); }
    public static void error(String fmt, Object... args) { LOG.error(fmt, args); }
}

Controller 中使用示例

@RestController
public class DemoController {
    @GetMapping("/log-test")
    public String test() {
        String msg = "Spring Boot + Log4j2 非同步日誌測試";
        L.trace(msg);
        L.debug(msg);
        L.info(msg);
        L.warn(msg);
        L.error(msg);
        L.info("帶參數日誌:userId={}, action={}", 1001, "LOGIN");
        return "OK";
    }
}

日誌級別體系與驗證

TRACE < DEBUG < INFO < WARN < ERROR < FATAL

配置 level="INFO" 時,只有 INFO、WARN、ERROR 會輸出。控制台輸出範例:

14:32:15.123 [http-nio-8080-exec-1] INFO  com.myapp.DemoController - Spring Boot + Log4j2 非同步日誌測試
14:32:15.124 [http-nio-8080-exec-1] WARN  com.myapp.DemoController - Spring Boot + Log4j2 非同步日誌測試
14:32:15.124 [http-nio-8080-exec-1] ERROR com.myapp.DemoController - Spring Boot + Log4j2 非同步日誌測試

檔案結構驗證

/var/log/myapp/
├── app-info.log
├── app-error.log
└── archive/
    └── 2024-01/
        ├── app-info-01-15-2024-1.log.gz
        └── app-error-01-15-2024-1.log.gz

進階技巧

1. MDC 追蹤請求鏈路

@Component
public class TraceFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        MDC.put("traceId", traceId);
        try { chain.doFilter(req, res); }
        finally { MDC.remove("traceId"); }
    }
}

Pattern 中加入 %X{traceId} 即可在日誌中串聯完整請求鏈路。

2. Spring Boot 自動配置整合

application.yml 中指定配置檔位置:

logging:
  config: classpath:log4j2.xml

3. 容器化部署注意事項

  • 日誌目錄掛載為 Volume,避免容器重啟丟失
  • 標準輸出(Console Appender)配合 Docker json-file 或 fluentd 驅動採集
  • 生產環境建議關閉 Console Appender,僅輸出檔案

總結

Log4j2 + Disruptor 非同步日誌是高併發系統的標配。核心要點:

  1. 引入 log4j-api、log4j-core、disruptor 三依賴
  2. 配置 RollingRandomAccessFile + AsyncRoot/AsyncLogger
  3. 善用變數、過濾器、滾動策略實現分級存儲
  4. 封裝工具類簡化業務代碼調用
  5. 結合 MDC 實現分散式追蹤

官方文檔:https://logging.apache.org/log4j/2.x/

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved