log4net 是 Apache Logging Services 專案的 .NET 移植版,源自經典的 Java log4j。它是一個**高效、靈活、分級**的日誌框架,支援多種輸出目標(控制台、文件、資料庫、網絡、事件日誌等),並通過外部配置文件實現**零代碼修改**調整日誌行為。
// NuGet (推薦)
Install-Package log4net
// 或 .NET CLI
dotnet add package log4net
引用後,專案會包含 `log4net.dll`。源碼可從 官網 獲取。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Logger │────▶│ Appender │────▶│ Layout │────▶│ Output │
│ (記錄器) │ │ (附著器) │ │ (佈局器) │ │ (輸出端) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
▲ ▲ ▲
│ │ │
│ ┌──────┴──────┐ │
│ │ Filter │ │
│ │ (過濾器) │ │
│ └─────────────┘ │
│ │
└─────────────── Repository (庫) ◀──────┘
(Logger 階層管理、配置存儲)
一個 Logger 可掛載多個 Appender,實現「一份日誌,多地輸出」。常用內建類型:
| Appender | 輸出目標 | 典型用途 |
|---|---|---|
ConsoleAppender | 控制台 | 開發調試、容器標準輸出 |
RollingFileAppender | 文件(支援滾動) | 生產環境主力,按大小/日期分割 |
FileAppender | 文件(無滾動) | 臨時/小型工具 |
AdoNetAppender | 關係型資料庫 | 集中存儲、SQL 查詢分析 |
EventLogAppender | Windows 事件日誌 | 系統級監控整合 |
SmtpAppender | 郵件 | 關鍵錯誤即時告警 |
UdpAppender / RemoteSyslogAppender | 網絡傳輸 | 集中日誌平台 |
AsyncAppender | 非同步包裝器 | 高併發解耦,緩衝隊列+專用線程 |
| 級別 | 數值 | 用途 | 生產建議 |
|---|---|---|---|
| ALL | -2147483648 | 啟用所有 | 僅極少數診斷場景 |
| DEBUG | -2147483640 | 詳細診斷資訊 | 開發/測試環境;生產關鍵模塊可啟用 |
| INFO | -2147483632 | 關鍵業務流程節點 | 生產預設級別 |
| WARN | -2147483624 | 潛在問題、降級、重試 | 生產必須記錄 |
| ERROR | -2147483616 | 業務失敗、異常捕獲 | 生產必須記錄,含堆疊 |
| FATAL | -2147483608 | 進程崩潰、不可恢復 | 極少見,觸發告警 |
| OFF | 2147483647 | 禁用所有 | 性能測試/基準測試 |
級別判斷規則:`Logger.Level ≤ Message.Level` 才輸出。例如 Logger 設 `INFO`,則 `DEBUG` 被過濾,`INFO`/`WARN`/`ERROR`/`FATAL` 輸出。
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<root>
<level value="INFO" />
<appender-ref ref="ConsoleAppender" />
</root>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
</log4net>
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
class Program {
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main() {
Log.Info("應用啟動");
Log.Debug("此行僅在 DEBUG 級別可見");
Log.Error("模擬錯誤", new InvalidOperationException("測試異常"));
}
}
2024-01-15 14:30:45,123 [1] INFO Program - 應用啟動
2024-01-15 14:30:45,125 [1] ERROR Program - 模擬錯誤
System.InvalidOperationException: 測試異常
at Program.Main() in ...
// 1. 類級別靜態字段(標準、推薦)
private static readonly ILog Log = LogManager.GetLogger(typeof(MyClass));
// 2. 字串名稱(動態、跨類共享)
var log = LogManager.GetLogger("MyApp.Audit");
// 3. 反射獲取調用類型(通用封裝基類用)
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
| 誤區 | 正確認知 |
|---|---|
| 以為 `Log.Debug(msg)` 會自動檢查級別 | 會檢查,但**參數已先求值**(字串插值/拼接已執行),必須用 `IsDebugEnabled` 守衛 |
| 配置文件放在專案根目錄未設 `Copy to Output Directory` | 輸出目錄找不到文件,啟用失敗;設為 `Copy if newer` |
| 以為 `BasicConfigurator` 能配置多 Logger 級別 | 僅配置根 Logger,精細控制需 XML 配置 |
| 直接 `new FileAppender()` 寫代碼配置 | 違背「外部配置」初衷,難以運維;僅限極簡工具 |