前言:為什麼選 Log4j?
作為 Java 老牌日誌框架,Log4j 憑藉:廣泛容器支持、高性能 (異步日誌、無鎖)、豐富輸出目標、靈活配置 (XML/Properties/JSON/YAML)、運行時動態調整級別,成為企業級應用首選。本文基於 Log4j 2.x (重寫架構) 系統梳理核心概念、配置詳解與實戰模板。
核心三要素
| 組件 | 角色 | 關鍵點 |
| Logger (記錄器) | 日誌輸入入口,層級過濾 | 命名通常為類全名,繼承體系 (root → com.foo → com.foo.Bar),級別:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL |
| Appender (輸出端) | 決定日誌去向 | Console、File、RollingFile (按大小/時間滾動)、JDBC、Socket、Syslog、Async (異步包裝)、自定義 |
| Layout (佈局) | 決定日誌格式 | PatternLayout (最常用)、JSONLayout、XMLLayout、HTMLLayout、SyslogLayout |
配置文件優先級與位置
- 類路徑下
log4j2.xml / log4j2.properties / log4j2.json / log4j2.yaml
- 系統屬性
-Dlog4j.configurationFile=path
- Servlet 容器自動掃描
WEB-INF/log4j2.xml
PatternLayout 佔位符速查
| 符號 | 含義 | 示例 |
| %d{pattern} | 時間 | %d{yyyy-MM-dd HH:mm:ss.SSS} |
| %p / %level | 級別 | ERROR |
| %c{length} | Logger 名 (可縮略) | %c{1} → 最後一段 |
| %m / %msg | 日誌消息 | 用戶登入失敗 |
| %t | 線程名 | http-nio-8080-exec-1 |
| %L / %line | 行號 | 123 (慎用,性能影響) |
| %M / %method | 方法名 | doGet (慎用) |
| %ex / %throwable | 異常堆棧 | %ex{full} 完整堆棧 |
| %n | 換行符 | 平台相關 |
生產級配置模板 (log4j2.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30"> <!-- 30秒自動重載 -->
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} %highlight{%p} [%t] %c{1.} - %m%n"/>
</Console>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%d %p [%c] - <%m>%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- 每天 -->
<SizeBasedTriggeringPolicy size="100 MB"/> <!-- 或達到100MB -->
</Policies>
<DefaultRolloverStrategy max="30"/> <!-- 保留30個 -->
</RollingFile>
<Async name="Async"> <!-- 異步包裝,高併發必備 -->
<AppenderRef ref="RollingFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="INFO"> <AppenderRef ref="Console"/> <AppenderRef ref="Async"/> </Root>
<Logger name="com.myapp.dao" level="DEBUG" additivity="false"> <AppenderRef ref="Async"/> </Logger>
<Logger name="org.hibernate.SQL" level="DEBUG" additivity="false"> <AppenderRef ref="Async"/> </Logger>
</Loggers>
</Configuration>
代碼中獲取 Logger (SLF4J 門面模式)
// 推薦:依賴 slf4j-api + log4j-slf4j-impl
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
log.debug("入參: {}", param);
log.error("處理失敗", exception); // 異常自動打印堆棧
進階特性
- 異步日誌 (Async Loggers):LMAX Disruptor 無鎖環形緩衝,吞吐量提升 10x+,需添加
disruptor 依賴並配置 `` 或全局系統屬性 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector。
- 標記:
log.info(MARKER, "msg"),配合 `MarkerFilter` 實現特定業務日誌單獨輸出 (如審計日誌)。
- 自定義 Appender:實現 `AbstractAppender` 推送至 ELK/Kafka/鉤釘機器人。
- GC/性能日誌:配合 `JVMInputArguments` 記錄啟動參數。
避坑指南
| 坑 | 後果 | 解決 |
| 類路徑存在多個配置文件 | 隨機生效 | 統一管理,排除傳遞依賴帶來的舊版 log4j 1.x jar |
| 大量使用 %L/%M | 性能驟降 | 僅 DEBUG 級別啟用,或使用異步日誌 |
| 未關閉 Context | 容器熱部署內存洩漏 | ServletContextListener 中調用 `LogManager.shutdown()` |
| Log4j 1.x 與 2.x 混用 | 類衝突、配置失效 | 全面遷移 2.x,使用 log4j-1.2-api 兼容舊代碼調用 |
結語
Log4j 2.x 以異步架構、豐富生態、零依賴核心,成為高性能 Java 日誌標桿。掌握「Logger-Appender-Layout」三元組、善用異步與滾動策略、門面解耦 (SLF4J),即可構建可觀測、可維運的日誌體系。
- 上一篇文章: Java 秘史:SWT 與 Swing 之爭背後的商業博弈與技術抉擇
- 下一篇文章: Java GUI 技術選型指南:AWT vs Swing vs SWT 深度對比與決策矩陣
Copyright ©
程式碼之家 All Rights Reserved