Condividi tramite


Implementare un provider di registrazione personalizzato in .NET

Esistono molti provider di registrazione disponibili per esigenze di registrazione comuni. Potrebbe essere necessario implementare un ILoggerProvider personalizzato quando uno dei provider disponibili non soddisfa le esigenze dell'applicazione. In questo articolo si apprenderà come implementare un provider di registrazione personalizzato che può essere usato per colorare i log nella console.

Consiglio

Il codice sorgente di esempio del provider di registrazione personalizzato è disponibile nel repository GitHub di Docs. Per altre informazioni, vedere GitHub: .NET Docs - Console Custom Logging.

Configurazione del logger personalizzata di esempio

L'esempio crea voci di console a colori diverse per livello di log e ID evento usando il tipo di configurazione seguente:

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
    };
}

Il codice precedente imposta il livello predefinito su Information, il colore su Greene il EventId viene 0in modo implicito.

Creare il logger personalizzato

Il nome della categoria di implementazione ILogger è in genere l'origine del log. Ad esempio, il tipo in cui viene creato il logger:

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();
        }
    }
}

Il codice precedente:

  • Crea un'istanza del logger per ogni nome di categoria.
  • Controlla _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel) in IsEnabled, in modo che ogni logLevel possa avere un logger univoco. In questa implementazione ogni livello di log richiede una voce di configurazione esplicita da registrare.

È consigliabile chiamare ILogger.IsEnabled all'interno delle implementazioni di ILogger.Log poiché Log può essere chiamato da qualsiasi consumatore e non c'è alcuna garanzia che sia stato verificato in precedenza. Il metodo IsEnabled deve essere molto veloce nella maggior parte delle implementazioni.

TState state,
Exception? exception,

Il logger viene creato con il name e un Func<ColorConsoleLoggerConfiguration>, restituendo la configurazione corrente e gestendo gli aggiornamenti ai valori di configurazione monitorati tramite il callback IOptionsMonitor<TOptions>.OnChange.

Importante

L'implementazione ILogger.Log controlla se è impostato il valore config.EventId. Quando config.EventId non è impostato o quando corrisponde esattamente a logEntry.EventId, il logger registra in modalità a colori.

Provider di logger personalizzato

L'oggetto ILoggerProvider è responsabile della creazione di istanze del logger. Non è necessario creare un'istanza del logger per categoria, ma ha senso per alcuni logger, ad esempio NLog o log4net. Questa strategia consente di scegliere diverse destinazioni di output di registrazione per categoria, come nell'esempio seguente:

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();
    }
}

Nel codice precedente, CreateLogger crea una singola istanza del ColorConsoleLogger per nome di categoria e la archivia nel ConcurrentDictionary<TKey,TValue>. Inoltre, l'interfaccia IOptionsMonitor<TOptions> è necessaria per aggiornare le modifiche all'oggetto ColorConsoleLoggerConfiguration sottostante.

Per controllare la configurazione del ColorConsoleLogger, definisci un alias sul suo provider:

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

La classe ColorConsoleLoggerProvider definisce due attributi con ambito classe:

La configurazione può essere specificata con qualsiasi provider di configurazione valido. Considerare il file di appsettings.json seguente:

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

In questo modo vengono configurati i livelli di log con i valori seguenti:

Il livello di log Information è impostato su DarkGreen, che esegue l'override del valore predefinito impostato nell'oggetto ColorConsoleLoggerConfiguration.

Utilizzo e registrazione del logger personalizzato

Per convenzione, la registrazione dei servizi per l'iniezione delle dipendenze avviene come parte della routine di avvio di un'applicazione. La registrazione si verifica nella classe Program o può essere delegata a una classe Startup. In questo esempio si eseguirà la registrazione direttamente dal Program.cs.

Per aggiungere il provider di registrazione personalizzato e il logger corrispondente, aggiungere un ILoggerProvider con ILoggingBuilder dal 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();

Il ILoggingBuilder crea una o più istanze di ILogger. Le istanze di ILogger vengono usate dal framework per registrare le informazioni.

La configurazione del file appsettings.json sostituisce i valori seguenti:

Per convenzione, i metodi di estensione su ILoggingBuilder vengono usati per registrare il provider personalizzato:

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;
    }
}

L'esecuzione di questa semplice applicazione produrrà un output a colori nella finestra della console in modo simile all'immagine seguente.

esempio di output del logger della console Color

Vedere anche