在 .NET 中实现自定义日志记录提供程序
有许多 日志记录提供程序 可用于常见日志记录需求。 当某个可用提供程序不符合应用程序需求时,可能需要实现自定义 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(
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,
记录器使用 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;
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;
}
}
运行此简单应用程序会将颜色输出呈现到控制台窗口,如下图所示: