Freigeben über


Implementieren eines benutzerdefinierten Protokollierungsanbieters in .NET

Viele Protokollierungsanbieter sind für allgemeine Protokollierungsanforderungen verfügbar. Möglicherweise müssen Sie eine benutzerdefinierte ILoggerProvider implementieren, wenn einer der verfügbaren Anbieter nicht ihren Anwendungsanforderungen entspricht. 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 beispielcode für den benutzerdefinierten Protokollierungsanbieter ist im Docs GitHub-Repositoryverfügbar. Weitere Informationen finden Sie unter GitHub: .NET-Dokumentation – Benutzerdefinierte Protokollierung in der Konsole.

Beispiel für eine benutzerdefinierte Loggerkonfiguration

Im Beispiel werden verschiedene Farbkonsoleneinträge pro Protokollebene 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 die Standardebene auf Information, die Farbe auf Greenfest, und die EventId ist implizit 0.

Erstellen des benutzerdefinierten Loggers

Der Name der ILogger-Implementierungskategorie ist normalerweise die Logquelle. Beispiel: Der Typ, in dem der Logger 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 Loggerinstanz pro Kategoriename.
  • Überprüft _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel) in IsEnabled, sodass jedes logLevel-Element über eine eindeutige Protokollierung verfügt. In dieser Implementierung erfordert jede Protokollebene einen expliziten Konfigurationseintrag zum Protokollieren.

Es empfiehlt sich, ILogger.IsEnabled innerhalb der ILogger.Log-Implementierungen aufzurufen, da Log von jedem Nutzer aufgerufen werden kann, und es gibt keine Garantien, dass er zuvor überprüft wurde. Die IsEnabled Methode sollte in den meisten Implementierungen sehr schnell sein.

TState state,
Exception? exception,

Der Logger wird mit dem name und einem Func<ColorConsoleLoggerConfiguration>instanziiert, der die aktuelle Konfiguration zurückgibt. Dadurch werden Aktualisierungen der Konfigurationswerte verarbeitet, die über den IOptionsMonitor<TOptions>.OnChange Rückruf überwacht werden.

Wichtig

Die ILogger.Log Implementierung überprüft, ob der config.EventId Wert festgelegt ist. Wenn config.EventId nicht festgelegt ist oder mit dem genauen logEntry.EventIdübereinstimmt, gibt der Logger die Protokolle in Farbe aus.

Benutzerdefinierter Loggeranbieter

Das ILoggerProvider-Objekt ist für das Erstellen von Loggerinstanzen verantwortlich. Es ist nicht erforderlich, eine Loggerinstanz pro Kategorie zu erstellen, aber es ist sinnvoll für einige Logger, z. B. NLog oder Log4net. Mit dieser Strategie können Sie unterschiedliche Protokollierungsausgabeziele pro Kategorie auswählen, wie im folgenden Beispiel gezeigt:

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 vorherigen Code erstellt CreateLogger eine einzelne Instanz des ColorConsoleLogger pro Kategorienamen und speichert sie im ConcurrentDictionary<TKey,TValue>. Darüber hinaus ist die IOptionsMonitor<TOptions> Schnittstelle erforderlich, um Änderungen an dem zugrunde liegenden ColorConsoleLoggerConfiguration-Objekt zu aktualisieren.

Um die Konfiguration der ColorConsoleLoggerzu steuern, definieren Sie einen Alias beim Anbieter.

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

Die ColorConsoleLoggerProvider-Klasse definiert zwei Klassenbereichsattribute:

Die Konfiguration kann mit jedem gültigen Konfigurationsanbieterfestgelegt werden. Betrachten Sie die folgende appsettings.json Datei:

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

Dadurch werden die Protokollebenen mit den folgenden Werten konfiguriert:

Die Information Protokollebene wird auf DarkGreenfestgelegt, wodurch der im ColorConsoleLoggerConfiguration-Objekt festgelegte Standardwert außer Kraft gesetzt wird.

Nutzung und Registrierung des benutzerdefinierten Loggers

Standardmäßig erfolgt das Registrieren von Diensten für die Abhängigkeitseinfügung im Rahmen der Startroutine einer Anwendung. Die Registrierung erfolgt in der Program Klasse oder kann an eine Startup Klasse delegiert 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 verwendet, um die Informationen zu protokollieren.

Die Konfiguration aus der datei appsettings.json setzt die folgenden Werte außer Kraft:

Standardmäßig 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 im folgenden Bild dargestellt.

Beispielausgabe der Protokollierung für die Farbkonsole

Siehe auch