生產環境日誌系統常遇到兩類「看似玄學、實則配置/環境問題」:日誌時間與系統時間相差 8 小時 (時區問題)、同一日誌重複打印多次 (Appender 重複引用)。本文記錄真實排查過程與根因修復方案。
-Duser.timezone。Log4j (log4j 1.x / log4j2) 獲取時間戳最終依賴 java.util.Date 或 System.currentTimeMillis(),格式化時使用 TimeZone.getDefault()。若 JVM 啟動時未檢測到正確時區,會回退到 **GMT (UTC)**。Tomcat 作為獨立進程,其啟動腳本未傳遞時區參數,導致 JVM 默認時區為 GMT,而 Eclipse 啟動時繼承了 IDE/系統環境時區 (Asia/Shanghai),故控制台正常、文件異常。
rem 在 set _EXECJAVA=... 等變量定義之後、執行啟動命令之前插入
set JAVA_OPTS=%JAVA_OPTS% -Duser.timezone=Asia/Shanghai
或直接在 set _EXECJAVA=... 後添加:
set _EXECJAVA=%_EXECJAVA% -Duser.timezone=Asia/Shanghai
建議創建 bin/setenv.sh (Tomcat 會自動加載):
#!/bin/bash
export JAVA_OPTS="$JAVA_OPTS -Duser.timezone=Asia/Shanghai"
賦予執行權限:chmod +x bin/setenv.sh。
重啟 Tomcat,日誌時間恢復北京時間。也可在應用啟動時打印驗證:log.info("JVM Default TimeZone: {}", TimeZone.getDefault().getID()); 應輸出 Asia/Shanghai。
注意:網上流傳的-Duser.timezone=GMT+08寫法**不標準**,Java 時區 ID 必須使用 IANA 時區數據庫格式 (如Asia/Shanghai、America/New_York),GMT+08可能在某些 JDK 版本無法正確識別夏令時規則。
2016-04-22 01:51:28,427 [DEBUG] ... HouseKeeper - Testing connection 2: True
2016-04-22 01:51:28,427 [DEBUG] ... HouseKeeper - Testing connection 2: True <-- 重複行
log4j.rootLogger=ERROR, stdout, R, proxool
log4j.logger.org.logicalcobwebs.proxool=DEBUG, proxool
rootLogger 關聯了 proxool Appender。org.logicalcobwebs.proxool Logger 顯式設置級別為 DEBUG,**並再次關聯了同一個 proxool Appender**。additivity=true (繼承父 Logger 的 Appender)。log4j.rootLogger=ERROR, stdout, R
log4j.logger.org.logicalcobwebs.proxool=DEBUG, proxool
log4j.rootLogger=ERROR, stdout, R, proxool
log4j.logger.org.logicalcobwebs.proxool=DEBUG, proxool
log4j.additivity.org.logicalcobwebs.proxool=false
原則:一個 Appender 只應被一個 Logger 直接引用,避免通過繼承鏈重複接收事件。同理,Log4j2 XML 配置中 <Logger additivity="false"> 同樣適用。
| 問題 | 核心原因 | 修復要點 |
|---|---|---|
| 日誌時間偏移 8h | Tomcat JVM 默認時區為 GMT | 啟動腳本強制 -Duser.timezone=Asia/Shanghai |
| 日誌重複輸出 | Logger 繼承 + 重複引用同一 Appender | 移除重複引用 或 設置 additivity=false |
| 日誌亂碼 | 文件編碼與 JVM file.encoding 不一致 | 統一 UTF-8,啟動參數 -Dfile.encoding=UTF-8 |
| 日誌丟失/不輸出 | 級別過高 / Appender 閾值過高 / 路徑無權限 | 檢查 Logger/Root 級別、Appender Threshold、磁盤權限 |
日誌系統是系統的「黑匣子」,時間準確、輸出唯一、編碼正確是其可用性的底線。將時區參數固化在啟動腳本、嚴格控制 Appender 引用拓撲、統一 UTF-8 編碼鏈路,能消除 90% 以上的日誌基礎設施故障。