# ===== 根 Logger:級別 + 多輸出端 =====
log4j.rootLogger=DEBUG, CONSOLE, FILE
# ===== Console 輸出端 =====
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c - %m%n
# ===== RollingFileAppender:按大小滾動 =====
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=${catalina.base}/logs/app.log # 路徑支援系統屬性
log4j.appender.FILE.MaxFileSize=10MB # 單文件最大
log4j.appender.FILE.MaxBackupIndex=10 # 保留備份數
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
# ===== 可選:DailyRollingFileAppender 按日期滾動 =====
# log4j.appender.DAILY=org.apache.log4j.DailyRollingFileAppender
# log4j.appender.DAILY.File=${catalina.base}/logs/app.log
# log4j.appender.DAILY.DatePattern='.'yyyy-MM-dd
# log4j.appender.DAILY.layout=org.apache.log4j.PatternLayout
# log4j.appender.DAILY.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n
# ===== 包級別級別控制 =====
log4j.logger.com.example.dao=DEBUG
log4j.logger.org.hibernate=WARN
log4j.logger.org.springframework=INFO
| 屬性 | 說明 | 推薦值 |
|---|---|---|
rootLogger | 全局最低級別 + 輸出端引用 | INFO, CONSOLE, FILE (生產) |
File | 日誌文件路徑 | 絕對路徑或 ${catalina.base}/logs/ |
MaxFileSize | 觸發滾動閾值 | 10MB~100MB |
MaxBackupIndex | 保留歷史文件數 | 10~30 |
DatePattern | DailyRolling 滾動頻率 | '.'yyyy-MM-dd (每天)、'.'yyyy-MM (每月) |
ConversionPattern | 輸出格式 | 含時間、線程、級別、類名、行號 %L、訊息 |
Threshold | Appender 級別過濾器 | 如 FILE.Threshold=WARN 僅記錄 WARN+ 到文件 |
public class DynamicLog4jConfig {
public static void configure(String logFilePath, String level, long maxFileSize, int maxBackup) {
Properties props = new Properties();
props.setProperty("log4j.rootLogger", level + ", CONSOLE, FILE");
props.setProperty("log4j.appender.CONSOLE", "org.apache.log4j.ConsoleAppender");
props.setProperty("log4j.appender.CONSOLE.layout", "org.apache.log4j.PatternLayout");
props.setProperty("log4j.appender.CONSOLE.layout.ConversionPattern", "%-4r [%t] %-5p %c - %m%n");
props.setProperty("log4j.appender.FILE", "org.apache.log4j.RollingFileAppender");
props.setProperty("log4j.appender.FILE.File", logFilePath);
props.setProperty("log4j.appender.FILE.MaxFileSize", maxFileSize + "KB");
props.setProperty("log4j.appender.FILE.MaxBackupIndex", String.valueOf(maxBackup));
props.setProperty("log4j.appender.FILE.layout", "org.apache.log4j.PatternLayout");
props.setProperty("log4j.appender.FILE.layout.ConversionPattern", "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n");
// 重新配置(會關閉舊 Appender,開啟新)
PropertyConfigurator.configure(props);
}
}
應用場景:管理後台動態調整日誌級別、路徑、滾動策略,無需重啟應用。
package com.example.init;
import javax.servlet.*;
import org.apache.log4j.PropertyConfigurator;
public class Log4jInitServlet implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
String prefix = sce.getServletContext().getRealPath("/");
String configFile = sce.getServletContext().getInitParameter("log4j-config-file");
// 例如 log4j-config-file WEB-INF/log4j.properties
if (configFile != null) {
String fullPath = prefix + configFile;
PropertyConfigurator.configure(fullPath);
System.out.println("Log4j 初始化完成: " + fullPath);
} else {
// 預設配置
BasicConfigurator.configure();
}
}
@Override public void contextDestroyed(ServletContextEvent sce) {
LogManager.shutdown(); // 關閉所有 Appender,釋放文件鎖
}
}
<context-param>
<param-name>log4j-config-file</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>com.example.init.Log4jInitServlet</listener-class>
</listener>
Servlet 3.0+ 可用 @WebListener 註解替代 web.xml。
<!-- Pattern 中加入 %X{requestId} -->
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c [%X{requestId}] - %m%n
// Filter 中設置
public class RequestIdFilter implements Filter {
@Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
String requestId = UUID.randomUUID().toString().substring(0, 8);
MDC.put("requestId", requestId);
try { chain.doFilter(req, res); }
finally { MDC.remove("requestId"); }
}
}
效果:日誌自動帶上請求唯一 ID,便於鏈路追蹤、ELK 收集分析。
| 特性 | Log4j 1.x (停維) | Log4j 2.x | Logback |
|---|---|---|---|
| 性能 | 同步阻塞 | 異步 Loggers (LMAX Disruptor) 極高吞吐 | 異步 Appender 良好 |
| 配置格式 | .properties/.xml | XML/JSON/YAML/Properties | XML/Groovy |
| 熱加載 | 不支援 | monitorInterval 秒級熱加載 | scanPeriod 支援 |
| Lambda 支援 | 無 | logger.debug(() -> "expensive") | 支援 |
| Spring Boot 默認 | 無 | 可選 | 默認 (經 SLF4J) |
強烈建議:新專案直接使用 **Spring Boot Starter Logging (Logback)** 或 **Log4j 2**;存量 Log4j 1.x 專案規劃遷移,僅需替換依賴、配置文件、import 包路徑,代碼幾乎無需變動(經 SLF4J 門面)。
File 屬性拼寫、Appender 是否被 rootLogger 引用。log4j.appender.FILE.encoding=UTF-8(Log4j 2.x),或確保 JVM -Dfile.encoding=UTF-8。MaxFileSize 單位為 KB/MB/GB,需帶單位;MaxBackupIndex 必須 > 0。
4. 類加載器洩漏:Web 應用關閉時調用 LogManager.shutdown()(在 ServletContextListener.contextDestroyed 中)。
5. 多應用共用日誌文件:極不推薦,改用各應用獨立文件 + 日誌收集系統 (Filebeat/Fluentd) 聚合。