Реализация настраиваемого поставщика логирования в .NET
Существует множество поставщиков ведения журналов, доступны для распространенных потребностей в ведении журнала. Возможно, вам потребуется реализовать пользовательскую ILoggerProvider, если один из доступных поставщиков не соответствует потребностям приложения. В этой статье вы узнаете, как реализовать настраиваемый поставщик логирования, который можно использовать для раскрашивания журналов в консоли.
Совет
Пример исходного кода поставщика ведения журнала доступен в репозитории GitHub. Дополнительные сведения см. в разделе GitHub: документация по .NET - пользовательское ведение журнала в консоли.
Пример конфигурации пользовательского средства ведения журнала
В примере создаются консольные записи с различными цветами для каждого уровня логирования и идентификатора события, используя следующий тип конфигурации:
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();
}
}
}
Предыдущий код:
- Создает экземпляр логгера по имени категории.
- Проверяет
_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)
вIsEnabled
, поэтому каждыйlogLevel
имеет уникальный средство ведения журнала. В этой реализации каждому уровню журнала требуется явная конфигурационная запись для ведения журнала.
Рекомендуется вызывать ILogger.IsEnabled в рамках реализации ILogger.Log, так как 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: тип
ColorConsoleLogger
не поддерживается в"browser"
. -
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.
Чтобы добавить настраиваемого поставщика логирования и соответствующий логгер, добавьте ILoggerProvider с ILoggingBuilder из HostingHostBuilderExtensions.ConfigureLogging(IHostBuilder, Action<ILoggingBuilder>):
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;
}
}
При выполнении этого простого приложения выходные данные цвета будут отображаться в окне консоли, аналогично следующему изображению:
Пример вывода цветного консольного логгера
См. также
- ведение журнала в .NET
- поставщики ведения журнала в .NET
- внедрение зависимостей в .NET
- Логирование с высокой производительностью в .NET