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

Log4j2 完整實戰教程:從入門到生產級配置最佳實踐

     編輯:Java 程式設計入門

Log4j2 核心優勢

  • 無鎖異步日誌:基於 LMAX Disruptor,吞吐量比 Log4j 1.x / Logback 高 10 倍+
  • 插件架構:Appender、Layout、Filter、Lookup 等全插件化,擴展極簡
  • 配置熱加載:monitorInterval 自動感知配置變更,無需重啟
  • 垃圾自由:關鍵路徑零對象分配,減輕 GC 壓力
  • Lambda 延遲求值:logger.debug(() -> expensiveComputation()) 避免無效字符串拼接

依賴配置 (Maven)


<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>

基礎使用:獲取 Logger 與日誌級別


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

public class Log4j2Demo {
    // 推薦:按類名獲取,支持層級繼承
    private static final Logger logger = LogManager.getLogger(Log4j2Demo.class);
    
    // 也可自定義名稱
    // private static final Logger logger = LogManager.getLogger("my.custom.logger");
    
    public void demo() {
        // 入口/出口追蹤 (TRACE 級別)
        logger.entry();  
        logger.entry("param1", "param2");
        
        // 標準級別 (由低到高)
        logger.trace("追蹤信息:方法進入,變量值={}", "value");
        logger.debug("調試信息:當前用戶ID={}", 1001);
        logger.info("業務信息:用戶[{}]登錄成功", "zhangsan");
        logger.warn("警告信息:緩存命中率降至 {}%", 45);
        logger.error("錯誤信息:數據庫連接失敗", new SQLException("Connection timeout"));
        logger.fatal("致命錯誤:系統即將關閉");
        
        // 顯式指定級別 (罕用)
        logger.log(Level.DEBUG, "手動指定級別");
        
        // 異常堆棧自動記錄
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            logger.catching(e);  // 等同於 logger.error("msg", e)
        }
        
        // 退出追蹤
        logger.exit();
        logger.exit("returnValue", result);
    }
}

日誌級別體系與繼承規則


OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL
  • 級別過濾:設置 Logger 級別為 INFO,則 TRACE/DEBUG 不會輸出
  • 加法性:默認 additivity="true",子 Logger 會向父 Logger (最終到 Root) 傳遞事件,導致重複輸出
  • 關閉加法性:<Logger name="com.myapp" level="DEBUG" additivity="false"> 避免雙重輸出

配置文件詳解 (log4j2.xml)

最小配置 (等同默認)


<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="60">
    <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="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

生產環境推薦配置 (詳解版)


<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="60">
    <!-- 全局變量定義 -->
    <Properties>
        <Property name="LOG_DIR">logs</Property>
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} %L %M - %msg%n</Property>
        <Property name="FILE_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} %L %M - %msg%n</Property>
    </Properties>
    
    <Appenders>
        <!-- 1. 控制台:僅輸出 WARN 以上,開發調試用 -->
        <Console name="Console" target="SYSTEM_OUT">
            <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </Console>
        
        <!-- 2. 普通日誌文件:每日滾動,保留 30 天,INFO 以上 -->
        <RollingFile name="RollingFile" 
            fileName="${LOG_DIR}/app.log"
            filePattern="${LOG_DIR}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="${FILE_PATTERN}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>  
                <SizeBasedTriggeringPolicy size="100MB"/>                 
            </Policies>
            <DefaultRolloverStrategy max="20"/>  
        </RollingFile>
        
        <!-- 3. 錯誤專用文件:單獨記錄 ERROR+,便於告警排查 -->
        <RollingFile name="ErrorFile"
            fileName="${LOG_DIR}/error.log"
            filePattern="${LOG_DIR}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${FILE_PATTERN}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="50MB"/>
            </Policies>
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>
        
        <!-- 4. 審計/業務專用:異步寫入,高吞吐 -->
        <Async name="AsyncAudit">
            <AppenderRef ref="AuditFile"/>
        </Async>
        <RollingFile name="AuditFile"
            fileName="${LOG_DIR}/audit.log"
            filePattern="${LOG_DIR}/audit-%d{yyyy-MM-dd}.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %msg%n"/>
        </RollingFile>
    </Appenders>
    
    <Loggers>
        <!-- 包級別配置:com.myapp.dao 只輸出 WARN+,減少 SQL 干擾 -->
        <Logger name="com.myapp.dao" level="WARN" additivity="false">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
        </Logger>
        
        <!-- 特定類 DEBUG -->
        <Logger name="com.myapp.service.OrderService" level="DEBUG" additivity="false">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
        </Logger>
        
        <!-- 審計日誌獨立路由 -->
        <Logger name="AUDIT" level="INFO" additivity="false">
            <AppenderRef ref="AsyncAudit"/>
        </Logger>
        
        <Root level="INFO">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

關鍵配置項深度解析

PatternLayout 佔位符速查表

佔位符含義示例
%d{pattern}時間%d{yyyy-MM-dd HH:mm:ss.SSS}
%t線程名main, http-nio-8080-exec-1
%-5level級別左對齊 5 寬INFO , DEBUG, ERROR
%logger{36}Logger 名稱,精簡到 36 字符c.m.s.OrderService
%L行號 (慎用,有性能開銷)123
%M方法名 (慎用)processOrder
%msg / %m日誌消息用戶登錄成功
%ex / %xEx異常堆棧 (含/不含包名)java.lang.NullPointerException...
%X{key}MDC 值 (如 traceId)%X{traceId}

Filter 過濾器類型

  • ThresholdFilter:級別閾值過濾
  • RegexFilter:正則匹配消息內容
  • MarkerFilter:標記過濾
  • ScriptFilter:Groovy/JS 腳本動態判斷
  • BurstFilter:突發控制,防止日志洪峰

滾動策略組合


<Policies>
    <TimeBasedTriggeringPolicy interval="1" modulate="true"/>  
    <SizeBasedTriggeringPolicy size="100MB"/>                 
    <CronTriggeringPolicy schedule="0 0 * * * ?"/>            
</Policies>

進階特性實戰

1. MDC (Mapped Diagnostic Context) 鏈路追蹤


// 請求進入時設置 (如 Filter/Interceptor)
MDC.put("traceId", UUID.randomUUID().toString());
MDC.put("userId", currentUser.getId());

try {
    logger.info("處理訂單請求");  // 自動包含 traceId, userId
    // 業務邏輯...
} finally {
    MDC.clear();  // 必須清理,防止線程池復用污染
}

// 配置中使用 %X{traceId} 輸出

2. 異步日誌 (Async Logger) - 高性能關鍵




<AsyncLogger name="com.myapp.highthroughput" level="INFO" additivity="false">
    <AppenderRef ref="RollingFile"/>
</AsyncLogger>


<Async name="AsyncFile">
    <AppenderRef ref="RollingFile"/>
</Async>

性能提示:異步日誌將日誌事件放入無鎖環形緩衝區,由專用線程批量寫入磁盤,主業務線程幾乎零延遲。需引入 Disruptor 依賴。

3. 自定義 Level 與 Lookup



<CustomLevels>
    <CustomLevel name="AUDIT" intLevel="350" />  
</CustomLevels>


logger.log(Level.getLevel("AUDIT"), "審計記錄");

// Lookup 動態值
<Property name="LOG_DIR">${sys:user.home}/logs</Property>  
<Property name="LOG_DIR">${env:LOG_PATH}</Property>          
<Property name="LOG_DIR">${k8s:podName}</Property>           

4. 程序化配置 (無 XML)


ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(Level.WARN)
    .add(builder.newAppender("Console", "CONSOLE")
        .addAttribute("target", "SYSTEM_OUT")
        .add(builder.newLayout("PatternLayout")
            .addAttribute("pattern", "%d{HH:mm:ss} %-5level %logger - %msg%n")))
    .add(builder.newRootLogger(Level.INFO)
        .add(builder.newAppenderRef("Console")));

Configurator.initialize(builder.build());

常見問題排查指南

❌ 現象:控制台無輸出 / 文件不生成

  • 檢查 log4j2.xml 是否在 classpath 根目錄 (src/main/resources)
  • 檢查 status="DEBUG" 觀察 Log4j2 內部啟動日誌
  • 確認無多個配置文件衝突 (log4j2.xml, log4j2-test.xml, log4j2.properties)

❌ 現象:日誌重複輸出兩遍

  • 設置 additivity="false" 在具體 Logger 上
  • 或移除 Root Logger 中的重複 AppenderRef

❌ 現象:異步日誌丟失 / 應用關閉未刷盤

  • 添加關閉鉤子:Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown))
  • Spring Boot 自動處理,無需手動

❌ 現象:類加載器洩漏 (Tomcat 熱部署)

  • Web 環境依賴 log4j-web 模塊自動清理
  • 或手動調用 LogManager.shutdown() 在 ServletContextListener.contextDestroyed

遷移指南:Log4j 1.x / Logback → Log4j2

  • API 兼容:log4j-1.2-api 橋接舊代碼 Logger.getLogger()
  • SLF4J 綁定:log4j-slf4j2-impl 替換 log4j-slf4j-impl
  • 配置轉換:工具 官方遷移指南

總結

Log4j2 以卓越性能、靈活配置、豐富生態成為 Java 日誌首選。掌握「分級路由、異步寫入、MDC 追蹤、熱加載」四大核心能力,配合合理的 Appender 組合(控制台+滾動文件+錯誤專用+審計異步),可構建生產級可觀測體系。建議在項目中統一接入 SLF4J 門面,底層無縫切換 Log4j2,享受最佳開發體驗。

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