首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

log4net 進階教學:多 Logger 儲存庫、動態配置與日誌自動維護

     編輯:ASP.NET 基礎

前言

log4net 預設單一 Logger 滿足大部分需求,但企業級應用常需:不同模組獨立日誌檔、不同等級閾值、動態新增 Logger、自動清理舊日誌。本文示範如何以程式碼動態建立 `ILoggerRepository`、配置 `RollingFileAppender` 實現按大小/日期滾動、自動限制檔案總數,免除人工維護。

動態取得/建立 Logger 的通用方法

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 設定範例

<appSettings>
  <add key="LogLevel" value="Info" />
  <add key="LogAppender" value="rollingfile,console" />
</appSettings>

RollingFileAppender 關鍵參數深度解析

參數說明自動維護效果
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最小鎖定,允許外部工具讀取/刪除避免日誌被佔用無法清理

兩種自動維護策略比較

  1. 固定檔名 + 限制備份數 (推薦):`StaticLogFileName=true` + `MaxSizeRollBackups=N`。
    優點:檔案總數固定、無需外部清理排程。
    缺點:最舊日誌會被覆蓋,極度重視歷史審計者不適用。
  2. 日期滾動 + 外部清理排程:`StaticLogFileName=false` + `RollingStyle=Date`。
    優點:完整保留每日/每小時檔案。
    缺點:需自行撰寫 Windows Service/排程刪除 N 天前檔案。

使用範例


// 業務模組 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 });

注意事項

  • 多執行緒競爭:`CreateRepository` 非執行緒安全,範例採雙重 try-catch 模式緩解;高併發建議啟動時預先建立所有 Repository。
  • 設定變更即時生效:`XmlConfigurator.ConfigureAndWatch` 僅支援 XML 設定檔;程式碼配置需自行實作 `FileSystemWatcher` 監聽 AppSettings 變更並重新 `Configure`。
  • 效能:`MinimalLock` 略微降低寫入效能,但換取可讀性;極高頻寫入(>10k/sec)建議改用 `AsyncForwardingAppender` + `BufferingForwardingAppender`。
  • .NET Core / 5+:建議改用 `Microsoft.Extensions.Logging` + `Serilog`/`NLog`,log4net 維護模式中。

總結

透過程式碼動態建立 `ILoggerRepository`、集中在 `AppSettings` 管理等級與 Appender、配置 `RollingFileAppender` 固定檔名與備份上限,即可實現「多模組隔離、動態配置、零人工維護」的企業級日誌系統。理解 `StaticLogFileName` 與 `MaxSizeRollBackups` 的互動關係,是自動維護的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved