共用方式為


在 .NET 中實作自定義記錄提供者

有許多 記錄提供者 可用於常見的記錄需求。 當其中一個可用的提供者不符合應用程式需求時,您可能需要實作自定義 ILoggerProvider。 在本文中,您將瞭解如何實作自定義記錄提供者,以在控制台中著色記錄。

提示

自訂記錄提供者範例原始程式碼可在 Docs GitHub 存放庫中取得,。 如需詳細資訊,請參閱 GitHub:.NET Docs - 主控台自定義記錄

範例自定義記錄器組態

此範例會使用以下組態類型,根據每個記錄層級和事件識別碼建立不同顏色的控制台項目:

using Microsoft.Extensions.Logging;

public sealed class ColorConsoleLoggerConfiguration
{
    public int EventId { get; set; }

    public Dictionary<LogLevel, ConsoleColor> LogLevelToColorMap { get; set; } = new()
    {
        [LogLevel.Information] = ConsoleColor.Green
    };
}

此程式代碼會將預設層級設定為 InformationGreen色彩,而 EventId 會隱含 0

建立自訂記錄器

ILogger 實作類別名稱通常是記錄來源。 例如,創建記錄器的類型:

using Microsoft.Extensions.Logging;

public sealed class ColorConsoleLogger(
    string name,
    Func<ColorConsoleLoggerConfiguration> getCurrentConfig) : ILogger
{
    public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default!;

    public bool IsEnabled(LogLevel logLevel) =>
        getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel);

    public void Log<TState>(
        LogLevel logLevel,
        EventId eventId,
        TState state,
        Exception? exception,
        Func<TState, Exception?, string> formatter)
    {
        if (!IsEnabled(logLevel))
        {
            return;
        }

        ColorConsoleLoggerConfiguration config = getCurrentConfig();
        if (config.EventId == 0 || config.EventId == eventId.Id)
        {
            ConsoleColor originalColor = Console.ForegroundColor;

            Console.ForegroundColor = config.LogLevelToColorMap[logLevel];
            Console.WriteLine($"[{eventId.Id,2}: {logLevel,-12}]");
            
            Console.ForegroundColor = originalColor;
            Console.Write($"     {name} - ");

            Console.ForegroundColor = config.LogLevelToColorMap[logLevel];
            Console.Write($"{formatter(state, exception)}");
            
            Console.ForegroundColor = originalColor;
            Console.WriteLine();
        }
    }
}

上述程式代碼:

  • 為每個類別名稱建立記錄器實例。
  • 檢查 IsEnabled中的 _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel),以確保每個 logLevel 都有一個獨特的日誌記錄器。 在此實作中,每個記錄層級都需要明確的設定項目以便記錄。

最好是在 ILogger.Log 實作內呼叫 ILogger.IsEnabled,因為任何使用者都可以呼叫 Log,且不保證先前已進行檢查。 IsEnabled 方法在大部分的實作中應該非常快速。

TState state,
Exception? exception,

記錄器使用 nameFunc<ColorConsoleLoggerConfiguration>初始化,傳回當前的組態,此過程處理透過 IOptionsMonitor<TOptions>.OnChange 回呼監控的組態值更新。

重要

ILogger.Log 實作會檢查是否已設定 config.EventId 值。 未設定 config.EventId 或符合確切 logEntry.EventId時,記錄器會以色彩記錄。

自訂記錄器提供者

ILoggerProvider 物件負責建立記錄器實例。 不需要為每個類別建立記錄器實例,但對於某些記錄器而言,例如 NLog 或 log4net 是合理的。 此策略可讓您為每個類別選擇不同的記錄輸出目標,如下列範例所示:

using System.Collections.Concurrent;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

[UnsupportedOSPlatform("browser")]
[ProviderAlias("ColorConsole")]
public sealed class ColorConsoleLoggerProvider : ILoggerProvider
{
    private readonly IDisposable? _onChangeToken;
    private ColorConsoleLoggerConfiguration _currentConfig;
    private readonly ConcurrentDictionary<string, ColorConsoleLogger> _loggers =
        new(StringComparer.OrdinalIgnoreCase);

    public ColorConsoleLoggerProvider(
        IOptionsMonitor<ColorConsoleLoggerConfiguration> config)
    {
        _currentConfig = config.CurrentValue;
        _onChangeToken = config.OnChange(updatedConfig => _currentConfig = updatedConfig);
    }

    public ILogger CreateLogger(string categoryName) =>
        _loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(name, GetCurrentConfig));

    private ColorConsoleLoggerConfiguration GetCurrentConfig() => _currentConfig;

    public void Dispose()
    {
        _loggers.Clear();
        _onChangeToken?.Dispose();
    }
}

在上述程式代碼中,CreateLogger 會為每個類別名稱建立 ColorConsoleLogger 的單一實例,並將它儲存在 ConcurrentDictionary<TKey,TValue>中。 此外,需要 IOptionsMonitor<TOptions> 介面,才能更新基礎 ColorConsoleLoggerConfiguration 對象的變更。

若要控制 ColorConsoleLogger的組態,您可以在其提供者上定義別名:

[UnsupportedOSPlatform("browser")]
[ProviderAlias("ColorConsole")]
public sealed class ColorConsoleLoggerProvider : ILoggerProvider

ColorConsoleLoggerProvider 類別會定義兩個類別範圍屬性:

可以藉由任何有效的 組態提供者來指定組態,。 請考慮下列 appsettings.json 檔案:

{
    "Logging": {
        "ColorConsole": {
            "LogLevelToColorMap": {
                "Information": "DarkGreen",
                "Warning": "Cyan",
                "Error": "Red"
            }
        }
    }
}

這會將記錄層級設定為下列值:

Information 記錄層級設定為 DarkGreen,這會覆寫 ColorConsoleLoggerConfiguration 對象中設定的預設值。

自訂記錄器的使用方式和註冊

依照慣例,註冊相依性插入的服務是應用程式啟動例程的一部分。 註冊會在 Program 類別中發生,或可以委派給 Startup 類別。 在此範例中,您將直接從 Program.cs註冊。

若要新增自定義記錄提供者和對應的記錄器,請從 HostingHostBuilderExtensions.ConfigureLogging(IHostBuilder, Action<ILoggingBuilder>)新增具有 ILoggingBuilderILoggerProvider

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

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.ClearProviders();
builder.Logging.AddColorConsoleLogger(configuration =>
{
    // Replace warning value from appsettings.json of "Cyan"
    configuration.LogLevelToColorMap[LogLevel.Warning] = ConsoleColor.DarkCyan;
    // Replace warning value from appsettings.json of "Red"
    configuration.LogLevelToColorMap[LogLevel.Error] = ConsoleColor.DarkRed;
});

using IHost host = builder.Build();

var logger = host.Services.GetRequiredService<ILogger<Program>>();

logger.LogDebug(1, "Does this line get hit?");    // Not logged
logger.LogInformation(3, "Nothing to see here."); // Logs in ConsoleColor.DarkGreen
logger.LogWarning(5, "Warning... that was odd."); // Logs in ConsoleColor.DarkCyan
logger.LogError(7, "Oops, there was an error.");  // Logs in ConsoleColor.DarkRed
logger.LogTrace(5, "== 120.");                    // Not logged

await host.RunAsync();

ILoggingBuilder 會建立一或多個 ILogger 實例。 架構會使用 ILogger 實例來記錄資訊。

來自 appsettings.json 檔案的組態會覆寫下列值:

依照慣例,ILoggingBuilder 上的擴充方法可用來註冊自定義提供者:

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

public static class ColorConsoleLoggerExtensions
{
    public static ILoggingBuilder AddColorConsoleLogger(
        this ILoggingBuilder builder)
    {
        builder.AddConfiguration();

        builder.Services.TryAddEnumerable(
            ServiceDescriptor.Singleton<ILoggerProvider, ColorConsoleLoggerProvider>());

        LoggerProviderOptions.RegisterProviderOptions
            <ColorConsoleLoggerConfiguration, ColorConsoleLoggerProvider>(builder.Services);

        return builder;
    }

    public static ILoggingBuilder AddColorConsoleLogger(
        this ILoggingBuilder builder,
        Action<ColorConsoleLoggerConfiguration> configure)
    {
        builder.AddColorConsoleLogger();
        builder.Services.Configure(configure);

        return builder;
    }
}

執行這個簡單的應用程式會將色彩輸出轉譯至主控台視窗,如下圖所示:

色彩控制台記錄器範例輸出

另請參閱