Log4j 2.x 推薦使用 XML、YAML、JSON 或 Properties。XML 功能最全、IDE 支持最好;Properties 簡潔但不支持部分高級特性(如異步、腳本過濾)。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_DIR">logs</Property>
<Property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<!-- 控制台 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${PATTERN}"/>
</Console>
<!-- 按天滾動,保留 30 天 -->
<RollingFile name="RollingFile" fileName="${LOG_DIR}/app.log"
filePattern="${LOG_DIR}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="${PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<!-- 錯誤級別單獨文件 -->
<RollingFile name="ErrorFile" fileName="${LOG_DIR}/error.log"
filePattern="${LOG_DIR}/error-%d{yyyy-MM-dd}.log.gz">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${PATTERN}"/>
<Policies><TimeBasedTriggeringPolicy/></Policies>
</RollingFile>
<!-- 異步包裝器:高吞吐低延遲 -->
<Async name="AsyncRoot">
<AppenderRef ref="RollingFile"/>
<AppenderRef ref="ErrorFile"/>
<AppenderRef ref="Console"/>
</Async>
</Appenders>
<Loggers>
<!-- 第三方庫級別控制 -->
<Logger name="org.springframework" level="INFO"/>
<Logger name="org.hibernate" level="WARN"/>
<Logger name="com.zaxxer.hikari" level="INFO"/>
<!-- 業務代碼 -->
<Logger name="com.mycompany" level="DEBUG" additivity="false">
<AppenderRef ref="AsyncRoot"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="AsyncRoot"/>
</Root>
</Loggers>
</Configuration>
| 元素 | 說明 |
|---|---|
| monitorInterval="30" | 熱加載間隔(秒),修改配置無需重啟。 |
| RollingFile + TimeBasedTriggeringPolicy | 按天切割,配合日期目錄歸檔。 |
| SizeBasedTriggeringPolicy | 單文件超過 100MB 強制滾動,防止單文件過大。 |
| ThresholdFilter | ERROR 專用文件,便於告警掃描。 |
| Async Appender | 使用 LMAX Disruptor 無鎖環形緩衝區,日志寫入不阻塞業務線程,吞吐提升 10 倍+。 |
| additivity="false" | 禁止向父 Logger 傳遞,避免重複輸出。 |
public class OrderService {
private static final Logger logger = LogManager.getLogger(OrderService.class);
// 或使用 Lombok @Slf4j 註解自動生成
}
// 差:無論級別皆執行拼接
logger.debug("Processing order " + orderId + " for user " + user.getName());
// 好:僅 DEBUG 級別啟用時執行 Lambda
logger.debug("Processing order {} for user {}", () -> orderId, () -> user.getName());
// 更好:參數化佔位符(Log4j 2 自動延遲計算)
logger.debug("Processing order {} for user {}", orderId, user::getName);
在 Layout 中使用 JSONLayout 或 LogstashLayout,配合 MDC 埋點:
MDC.put("traceId", traceId);
MDC.put("userId", userId);
try {
logger.info("Order created");
} finally {
MDC.clear();
}
使用 Spring Profile 激活不同配置文件:log4j2-spring.xml 中引用 。
使用 JDBCAppender 配合 BufferSize 批量提交,避免每條日志一次事務:
<JDBC name="Database" tableName="sys_log" bufferSize="100">
<DataSource jndiName="java:comp/env/jdbc/LogDS" />
<Column name="created" pattern="%d{yyyy-MM-dd HH:mm:ss}"/>
<Column name="level" pattern="%level"/>
<Column name="logger" pattern="%logger{36}"/>
<Column name="message" pattern="%msg"/>
<Column name="trace_id" pattern="%X{traceId}"/>
</JDBC>
生產環境推薦:KafkaAppender → Logstash → Elasticsearch → Kibana,實現日志集中化、全文檢索、告警儀表盤。
log4j-1.2-api 橋接舊代碼,統一遷移至 2.x。immediateFlush="false" 配合 Async 緩衝,極大提升吞吐。log4j2.formatMsgNoLookups=true 或移除 JndiLookup 類。Log4j 2.x 憑藉異步無鎖架構、豐富 Appender 生態、熱加載、JSON/結構化輸出,成為 Java 生態事實標準。掌握「分級輸出、異步解耦、結構化字段、集中化采集」四大原則,構建可觀測、高性能、易運維的日志體系。