log4net 預設單一 Logger 滿足大部分需求,但企業級應用常需:不同模組獨立日誌檔、不同等級閾值、動態新增 Logger、自動清理舊日誌。本文示範如何以程式碼動態建立 `ILoggerRepository`、配置 `RollingFileAppender` 實現按大小/日期滾動、自動限制檔案總數,免除人工維護。
using log4net;
using log4net.Repository;
using log4net.Core;
using log4net.Appender;
using log4net.Layout;
using System.Configuration;
public static class LogHelper
{
public static ILog GetLogger(string repositoryName = "")
{
if (string.IsNullOrEmpty(repositoryName)) return LogManager.GetLogger("Default");
ILoggerRepository repository = null;
try { repository = LogManager.GetRepository(repositoryName); }
catch { }
// 找到現有儲存庫直接取得 Logger
if (repository != null) return LogManager.GetLogger(repositoryName, "Default");
// 不存在則建立(多執行緒下可能競爭,雙重檢查)
try { repository = LogManager.CreateRepository(repositoryName); }
catch { repository = LogManager.GetRepository(repositoryName); }
// 1. 設定閾值等級(從 AppSettings 讀取)
var levelStr = ConfigurationManager.AppSettings["LogLevel"]?.ToLower();
Level level = levelStr switch
{
"all" => Level.All,
"debug" => Level.Debug,
"info" => Level.Info,
"warn" => Level.Warn,
"error" => Level.Error,
"fatal" => Level.Fatal,
"off" => Level.Off,
_ => Level.All
};
repository.Threshold = level;
// 2. 依 AppSettings 動態加入 Appender
var appenderStr = ConfigurationManager.AppSettings["LogAppender"]?.ToLower();
var appenders = string.IsNullOrEmpty(appenderStr) ? new[] { "rollingfile" } : appenderStr.Split(',');
foreach (var a in appenders)
{
switch (a.Trim())
{
case "rollingfile": LoadRollingFileAppender(repository); break;
case "console": LoadConsoleAppender(repository); break;
case "trace": LoadTraceAppender(repository); break;
}
}
return LogManager.GetLogger(repositoryName, "Default");
}
// --- Appender 建立方法 ---
private static void LoadRollingFileAppender(ILoggerRepository repo)
{
var appender = new RollingFileAppender
{
Name = "RollingFile",
File = "Logs/日志.log", // 固定檔名,配合 StaticLogFileName=true
AppendToFile = true,
LockingModel = new FileAppender.MinimalLock(),
RollingStyle = RollingFileAppender.RollingMode.Composite,
DatePattern = "yyyy-MM-dd HH'時.log'",
MaxSizeRollBackups = 1000, // 最大備份數
MaximumFileSize = "500KB", // 單檔上限
StaticLogFileName = true, // 關鍵:固定檔名,超過備份數自動覆蓋最舊
Layout = new PatternLayout("%n【記錄時間】%date%n【描述】%message%n")
};
appender.ActivateOptions();
BasicConfigurator.Configure(repo, appender);
}
private static void LoadConsoleAppender(ILoggerRepository repo)
{
var appender = new ConsoleAppender { Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline") };
appender.ActivateOptions();
BasicConfigurator.Configure(repo, appender);
}
private static void LoadTraceAppender(ILoggerRepository repo)
{
var appender = new TraceAppender { Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline") };
appender.ActivateOptions();
BasicConfigurator.Configure(repo, appender);
}
}
<appSettings>
<add key="LogLevel" value="Info" />
<add key="LogAppender" value="rollingfile,console" />
</appSettings>
| 參數 | 說明 | 自動維護效果 |
|---|---|---|
| StaticLogFileName = true | 固定主檔名為 `日志.log`,舊檔自動更名 `日志.log.1`, `日志.log.2`... | 配合 MaxSizeRollBackups 形成循環佇列,超過數量自動刪除最舊 |
| MaxSizeRollBackups = 1000 | 最大備份檔案數(含主檔) | 上限 1000 檔,防止磁碟爆滿 |
| MaximumFileSize = 500KB | 單一檔案大小上限 | 達標即滾動,控制單檔大小 |
| RollingStyle = Composite | 同時依大小與日期滾動 | 兼顧時間與大小維度 |
| DatePattern | 日期滾動命名格式 | 如 `yyyy-MM-dd HH'時.log'` 產生 `日志.log.2024-01-01 12時.log` |
| LockingModel = MinimalLock | 最小鎖定,允許外部工具讀取/刪除 | 避免日誌被佔用無法清理 |
// 業務模組 A
private static readonly ILog logA = LogHelper.GetLogger("ModuleA");
logA.Info("訂單建立成功", new { OrderId = 123 });
// 業務模組 B(獨立檔案、獨立等級)
private static readonly ILog logB = LogHelper.GetLogger("ModuleB");
logB.Debug("快取命中率", new { HitRate = 0.95 });
透過程式碼動態建立 `ILoggerRepository`、集中在 `AppSettings` 管理等級與 Appender、配置 `RollingFileAppender` 固定檔名與備份上限,即可實現「多模組隔離、動態配置、零人工維護」的企業級日誌系統。理解 `StaticLogFileName` 與 `MaxSizeRollBackups` 的互動關係,是自動維護的關鍵。