有很多 日志记录提供程序 可用于常见日志记录需求。 如果某个可用的提供程序不满足你的应用程序需要,则你可能需要实现自定义的 ILoggerProvider 。 在本文中,你将学习如何实现可用于在控制台中为日志着色的自定义日志记录提供程序。

Docs Github 存储库中提供了自定义日志记录提供程序示例源代码。 有关详细信息,请参阅 GitHub:.NET Docs - 控制台自定义日志记录

示例自定义记录器配置

此示例会使用以下配置类型为每个日志级别和事件 ID 创建不同的颜色控制台条目:

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

前面的代码将默认级别设置为 Information ,将颜色设置为 Green ,而且 EventId 隐式设置为 0

创建自定义记录器

ILogger 实现类别名称通常是日志记录源。 例如,创建记录器的类型:

using Microsoft.Extensions.Logging; public sealed class ColorConsoleLogger : ILogger private readonly string _name; private readonly Func<ColorConsoleLoggerConfiguration> _getCurrentConfig; public ColorConsoleLogger( string name, Func<ColorConsoleLoggerConfiguration> getCurrentConfig) => (_name, _getCurrentConfig) = (name, getCurrentConfig); 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 方法应该非常快。

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

    记录器使用 name Func<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 类定义了两个类范围的属性:

  • UnsupportedOSPlatformAttribute "browser" 中不支持 ColorConsoleLogger 类型。
  • ProviderAliasAttribute :配置节可使用 "ColorConsole" 键定义选项。
  • 可通过任何有效的 配置提供程序 指定配置。 请考虑使用以下 appsettings.json 文件:

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

    这会将日志级别配置为以下值:

  • LogLevel.Information : ConsoleColor.DarkGreen
  • LogLevel.Warning : ConsoleColor.Cyan
  • LogLevel.Error : ConsoleColor.Red
  • Information 日志级别设置为 DarkGreen ,这将覆盖在 ColorConsoleLoggerConfiguration 对象中设置的默认值。

    自定义记录器的使用和注册

    根据约定,在应用程序启动例程中注册服务以进行依赖项注入。 注册在 Program 类中进行,还可能委托给 Startup 类。 本示例将直接从 Program.cs 进行注册。

    若要添加自定义日志记录提供程序和相应的记录器,请从 HostingHostBuilderExtensions.ConfigureLogging(IHostBuilder, Action<ILoggingBuilder>) 使用 ILoggingBuilder 添加 ILoggerProvider

    using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using IHost host = Host.CreateDefaultBuilder(args) .ConfigureLogging(builder => builder.ClearProviders() .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; .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 文件中的配置会替代以下值:

  • LogLevel.Warning : ConsoleColor.DarkCyan
  • LogLevel.Error : ConsoleColor.DarkRed
  • 按照约定, 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;

    运行此简单应用程序将把颜色输出呈现到控制台窗口,如下图所示:

  • .NET 中的日志记录
  • .NET 中的日志记录提供程序
  • .NET 中的依赖关系注入
  • .NET 中的高性能日志记录
  •