Implementieren eines benutzerdefinierten Protokollierungsanbieters in .NET
Für Ihre allgemeinen Protokollierungsanforderungen stehen viele Protokollierungsanbieter zur Verfügung. Sie sollten einen benutzerdefinierten ILoggerProvider implementieren, wenn einer der folgenden Anbieter den Anforderungen für Ihre Anwendung nicht erfüllen kann. In diesem Artikel erfahren Sie, wie Sie einen benutzerdefinierten Protokollierungsanbieter implementieren, der zum Einfärben von Protokollen in der-Konsole verwendet werden kann.
Tipp
Der Beispielquellcode des benutzerdefinierten Protokollierungsanbieters ist im GitHub-Repository „Docs“ verfügbar. Weitere Informationen finden Sie unter GitHub: .NET-Dokumentation – Benutzerdefinierte Protokollierung in der Konsole.
Beispielkonfiguration für benutzerdefinierte Protokollierung
Im Beispiel werden unterschiedliche Farbkonsoleneinträge pro Protokolliergrad und Ereignis-ID mithilfe des folgenden Konfigurationstyps erstellt:
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
};
}
Der vorangehende Code legt den Standardprotokolliergrad auf Information
und die Farbe auf Green
fest, und EventId
ist implizit 0
.
Erstellen der benutzerdefinierten Protokollierung
Der Kategoriename der ILogger
-Implementierung ist in der Regel die Protokollierungsquelle. Beispielsweise der Typ, in dem die Protokollierung erstellt wird:
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();
}
}
}
Der vorangehende Code:
- Erstellt eine Protokollierungsinstanz pro Kategoriename.
- Überprüft
_getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel)
inIsEnabled
, sodass jedeslogLevel
-Element über eine eindeutige Protokollierung verfügt. Bei dieser Implementierung erfordert jede Protokollebene einen expliziten Konfigurationseintrag zum Protokollieren.
Es ist eine bewährte Methode, ILogger.IsEnabled innerhalb von ILogger.Log-Implementierungen aufzurufen, da Log
von jedem Consumer aufgerufen werden kann, und es keine Garantien gibt, dass es zuvor überprüft wurde. Die IsEnabled
-Methode sollte in den meisten Implementierungen sehr schnell sein.
TState state,
Exception? exception,
Die Protokollierung wird mit dem name
und einer Func<ColorConsoleLoggerConfiguration>
instanziiert, wodurch die aktuelle Konfiguration zurückgegeben wird. Damit werden Aktualisierungen der Konfigurationswerte gemäß der Überwachung durch den Rückruf von IOptionsMonitor<TOptions>.OnChange behandelt.
Wichtig
Die ILogger.Log-Implementierung überprüft, ob der config.EventId
-Wert festgelegt ist. Wenn config.EventId
nicht festgelegt ist oder genau mit logEntry.EventId
übereinstimmt, erfolgt die Protokollierung in Farbe.
Benutzerdefinierter Protokollierungsanbieter
Das ILoggerProvider
-Objekt ist für die Erstellung der Protokollierungsinstanzen verantwortlich. Es muss keine Protokollierungsinstanz pro Kategorie erstellt werden. Dies ist jedoch für einige Protokollierungen wie NLog oder log4net sinnvoll. Mit dieser Strategie können Sie verschiedene Protokollierungsausgabeziele wie im folgenden Beispiel pro Kategorie auswählen:
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();
}
}
Im Code oben erstellt CreateLogger eine einzelne Instanz von ColorConsoleLogger
pro Kategoriename und speichert sie in ConcurrentDictionary<TKey,TValue>
. Außerdem ist die IOptionsMonitor<TOptions>-Schnittstelle erforderlich, um Änderungen am zugrunde liegenden ColorConsoleLoggerConfiguration
-Objekt zu aktualisieren.
Um die Konfiguration von ColorConsoleLogger
zu steuern, definieren Sie einen Alias für den zugehörigen Anbieter:
[UnsupportedOSPlatform("browser")]
[ProviderAlias("ColorConsole")]
public sealed class ColorConsoleLoggerProvider : ILoggerProvider
Die ColorConsoleLoggerProvider
-Klasse definiert zwei klassenspezifische Attribute:
- UnsupportedOSPlatformAttribute: Für den Typ
ColorConsoleLogger
gibt es keine Unterstützung in"browser"
. - ProviderAliasAttribute: In Konfigurationsabschnitten können Optionen mithilfe des Schlüssels
"ColorConsole"
definiert werden.
Die Konfiguration kann mit einem beliebigen gültigen Konfigurationsanbieter angegeben werden. Sehen Sie sich die nachfolgende Datei appsettings.json an:
{
"Logging": {
"ColorConsole": {
"LogLevelToColorMap": {
"Information": "DarkGreen",
"Warning": "Cyan",
"Error": "Red"
}
}
}
}
Dadurch werden die Protokollebenen mit den folgenden Werten konfiguriert:
- LogLevel.Information: ConsoleColor.DarkGreen
- LogLevel.Warning: ConsoleColor.Cyan
- LogLevel.Error: ConsoleColor.Red
Die Protokollebene Information ist auf DarkGreen festgelegt, wodurch der im Objekt ColorConsoleLoggerConfiguration
festgelegte Standardwert überschrieben wird.
Verwendung und Registrierung der benutzerdefinierten Protokollierung
Die Registrierung von Diensten für die Abhängigkeitsinjektion erfolgt, gemäß Konvention, als Teil Startroutine einer Anwendung. Die Registrierung erfolgt in der Program
Klasse oder kann an eine Klasse delegiert Startup
werden. In diesem Beispiel registrieren Sie sich direkt über program.cs.
Fügen Sie ILoggerProvider mit ILoggingBuilder aus HostingHostBuilderExtensions.ConfigureLogging(IHostBuilder, Action<ILoggingBuilder>) hinzu, um die benutzerdefinierten Protokollierungsanbieter und die entsprechenden Protokollierungen hinzuzufügen:
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
erstellt mindestens eine ILogger
-Instanz. Die ILogger
-Instanzen werden vom Framework zum Protokollieren der Informationen verwendet.
Die Konfiguration in der Datei appsettings.json überschreibt die folgenden Werte:
Gemäß Konvention werden Erweiterungsmethoden für ILoggingBuilder
verwendet, um den benutzerdefinierten Anbieter zu registrieren:
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;
}
}
Wenn Sie diese einfache Anwendung ausführen, wird die Farbausgabe im Konsolenfenster ähnlich wie in der folgenden Abbildung dargestellt: