CodeGym /課程 /C# SELF /記錄日誌: Microsoft.Extensions.Logging

記錄日誌: Microsoft.Extensions.Logging

C# SELF
等級 64, 課堂 0
開放

1. 介紹

在程式設計中記錄日誌不只是「在控制台輸出點東西」。記錄日誌是你的黑匣子、GPS 追蹤器和儀表板合而為一。沒有日誌,大型程式會變成謎一般的黑盒:「為什麼服務掛了?」「為什麼使用者沒收到郵件?」「到底有人在過去 3 個月啟動過這個模組嗎?」— 這些問題通常只有在日誌被保存並可取得時才能回答。

為什麼實際上需要記錄日誌?

錯誤查找與診斷
如果程式當機 — 日誌會告訴你在哪裡以及為什麼。如果程式沒當機但行為怪異 — 日誌會指出導致問題的步驟。

狀態監控
透過日誌可以知道系統現在是否運作、伺服器請求量多不多、是否有錯誤發生、誰在做什麼。

安全性
記錄未授權存取嘗試、可疑活動、認證錯誤。

審計
誰、做了什麼、何時做的。如果一個惡意管理員離職並刪除了資料,透過日誌可以恢復一切(或者至少了解他做了什麼)。

開發與運維支援
日誌不只是給程式設計師看的,還給測試人員、運維、系統管理員。六個月後你會對自己說:「謝謝你加了日誌!」

從 Console.WriteLine 到生產級日誌系統

新手的第一反應:「就用 Console.WriteLine 不就行了?」對於小型教學程式這確實夠用。但當應用在伺服器上運行、並行執行、或有數十甚至數百名使用者時,控制台就不夠用了。我們需要:

  • 區分重要資訊和除錯資訊。
  • 把日誌不只輸出到控制台,還要寫到檔案、資料庫、集中式系統。
  • 調整日誌詳細等級(最少 — 只有錯誤,最多 — 全部訊息)。
  • 自動在記錄中補上日期、時間、額外資訊。
  • 靈活配置。
  • 最重要的是 — 不要每次想把日誌導到別處就修改程式碼。

這就是「真正」日誌記錄器的時代開始的地方。

2. .NET 現代日誌系統基礎

在 .NET 生態系裡有一個標準、強大且靈活的日誌框架 — Microsoft.Extensions.Logging。它是隨著 ASP.NET Core 出現的一波新型 .NET 函式庫的一部分,但現在到處都能用:伺服器、桌面、甚至行動應用。

這個框架的優點?

  • 抽象化 — 不把你綁定到某個具體實作(logger 可以寫檔、寫控制台、寫雲端,或同時寫到多個地方)。
  • 支援日誌等級(Trace, Debug, Information, Warning, Error, Critical)。
  • 可注入到 DI 容器並整合到所有現代 .NET 應用。
  • 豐富的擴充生態:支援結構化日誌、高級格式化器和整合。

主要概念和類別

讓我們認識一些操作 Microsoft.Extensions.Logging 時會用到的關鍵物件:

類別/介面 用途
ILogger<T>
為某個類別提供類型化的日誌介面
ILogger
非泛型的日誌介面
ILoggerFactory
用來建立 logger 實例的工廠
ILoggingBuilder
允許在應用中設定日誌
LogLevel
日誌等級列舉 (Trace, Debug, Information, ...)

日誌等級

按重要性分級可以讓你過濾「噪音」並快速找到想要的訊息:

等級 (LogLevel) 何時使用?
Trace
最詳細的除錯訊息,「噪音」,時間性資料
Debug
主要的除錯資訊
Information
正常運作的關鍵事件訊息
Warning
潛在問題的警告,但系統仍在運作
Error
需要關注的錯誤,但應用仍在運行
Critical
危及整個系統的致命錯誤

3. 實作:在我們的應用中加入日誌

我們不寫抽象程式碼,改用一個示範應用繼續擴充。假設我們已有一個簡單的 Calculator 類別,並會在課程中逐步擴充它。

範例:基本計算器

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
    // 其它方法...
}

現在在裡面加入日誌。為此我們需要介面 ILogger<Calculator>,從外部取得(例如透過 Dependency Injection, DI)。

using Microsoft.Extensions.Logging;

public class Calculator
{
    private readonly ILogger<Calculator> _logger;

    public Calculator(ILogger<Calculator> logger)
    {
        _logger = logger;
    }

    public int Add(int a, int b)
    {
        int result = a + b;
        _logger.LogInformation("執行加法: {A} + {B} = {Result}", a, b, result);
        return result;
    }
}

有趣的事實:
logger 支援模板和命名參數({A}, {B}, {Result}),而不是字串串接,這讓日誌結構化、便於後續自動處理與搜尋。

4. 如何在控制台應用中建立並設定 logger

1. 引入 NuGet 套件

你的專案會需要:

  • Microsoft.Extensions.Logging
  • Microsoft.Extensions.Logging.Console(如果想輸出到控制台)
  • (可選) 其他 provider,如果需要的話

2. 設定 logger

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// 建立 DI 容器
var serviceProvider = new ServiceCollection()
    .AddLogging(builder => {
        builder.AddConsole(); // 輸出到控制台
        builder.SetMinimumLevel(LogLevel.Debug); // 最低日誌等級
    })
    .BuildServiceProvider();

// 取得指定型別的 logger 實例
var logger = serviceProvider.GetRequiredService<ILogger<Calculator>>();

var calculator = new Calculator(logger);
calculator.Add(5, 3); // 會在日誌中看到訊息

新手常犯的錯誤
「為什麼日誌沒出現在控制台?」— 檢查是否加入了需要的 provider (.AddConsole()),以及最低日誌等級是否設定正確 (SetMinimumLevel)。如果等級設定得太高,訊息會被「過濾掉」!

5. 有用的小細節

記錄錯誤與非標準情況

假設我們要記錄除以零的情況。加入相應的方法:

public int Divide(int a, int b)
{
    if (b == 0)
    {
        _logger.LogError("嘗試除以零! a={A}", a);
        throw new DivideByZeroException();
    }
    int result = a / b;
    _logger.LogInformation("執行除法: {A} / {B} = {Result}", a, b, result);
    return result;
}

為什麼要這樣做?
在真實應用中,當出現問題時,具有 Error 等級的日誌通常會被特別關注:它們會自動發送給管理員、在監控中突出顯示,並用於 alert/通知。

使用類別與標籤 (scopes)

.NET 的 logger 支援所謂的 scopes — 這是會自動加入到在某個程式區塊內所有日誌的額外 metadata。例如處理一個 web 請求或使用者 session 時,可以在 scope 裡加入其識別碼。

using (_logger.BeginScope("UserId: {UserId}", 42))
{
    _logger.LogInformation("開始處理使用者資料");
    // ...
}

區塊內的所有訊息都會帶上標籤 UserId: 42,之後能幫助依使用者或操作找到相關日誌。

範例:日誌等級的實際運作

_logger.LogTrace("這是 Trace — 幾乎沒人會看到");
_logger.LogDebug("這是 Debug — 給開發者看的");
_logger.LogInformation("這是 Information — 正常運作的事件");
_logger.LogWarning("這是 Warning — 可能的問題警告");
_logger.LogError("這是 Error — 需要注意的錯誤");
_logger.LogCritical("這是 Critical — 系統著火,需要消防隊!");

如果你設定了 SetMinimumLevel(LogLevel.Information),那你只會看到 Information, Warning, Error, Critical 這些等級的訊息。

技巧:
在開發階段保留 Trace 和 Debug 以利深度診斷;在生產環境通常只打開 Information 及以上,避免日誌體積爆炸並從「噪音」中漏掉重要資訊。

視覺化示意:現代日誌架構

graph TD
A[應用程式程式碼] --ILogger<YourClass>--> B[Microsoft.Extensions.Logging]
B --> C1[Console Provider]
B --> C2[File Provider]
B --> C3[Cloud/Database Provider]
C1 -.-> D1[日誌到控制台]
C2 -.-> D2[日誌到檔案]
C3 -.-> D3[日誌到監控系統]

subgraph Providers
    C1
    C2
    C3
end

6. 額外功能與擴充

結構化日誌:
參數的值可以不只存在字串裡,還可以作為鍵值對保存,這讓你可以基於參數進行搜尋與彙總(例如透過 Seq、ELK/ElasticSearch 或 Application Insights)。

日誌 Provider:
你可以加入很多不同的 provider:檔案型、Windows EventLog、Azure 等等。

透過 appsettings.json 配置日誌
在 ASP.NET Core 裡日誌可以透過設定檔靈活配置,無需重新編譯應用程式。

透過配置設定最低日誌等級的範例 (appsettings.json):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "MyApp.Calculator": "Debug",
      "Microsoft": "Warning"
    }
  }
}

7. 使用 Microsoft.Extensions.Logging 時常見錯誤

錯誤 №1: 選錯日誌等級。
用 LogInformation 來記錄錯誤而不是 LogError 或 LogCritical 會讓在生產環境中找問題變得困難。

錯誤 №2: 忽視結構化日誌。
用字串串接而不是使用帶 placeholder 的模板({Parameter})會失去結構化日誌的好處,比如基於參數的搜尋。

錯誤 №3: 錯誤設定日誌等級。
如果最低等級設定得太高(例如用 Warning 而不是 Debug),重要訊息可能會被過濾掉。

錯誤 №4: 過多或過少的日誌。
在生產環境記錄過於詳細(例如開啟 Trace)會製造「噪音」,而日誌不足又會讓診斷變得困難。

2
任務
C# SELF, 等級 64, 課堂 0
上鎖
使用 'Microsoft.Extensions.Logging' 進行基礎日誌記錄
使用 'Microsoft.Extensions.Logging' 進行基礎日誌記錄
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION