Condividi tramite


Formattazione del log della console

In .NET 5, il supporto per la formattazione personalizzata è stato aggiunto ai log della console nello spazio dei Microsoft.Extensions.Logging.Console nomi. Sono disponibili tre opzioni di formattazione predefinite: Simple, Systemde Json.

Importante

In precedenza, l'enumerazione ConsoleLoggerFormat consentiva la selezione del formato di log desiderato: leggibile, ovvero Default, oppure singola riga, nota anche come Systemd. Tuttavia, questi non erano personalizzabili e sono ora obsoleti.

In questo articolo verranno fornite informazioni sui formattatori di log della console. Il codice sorgente di esempio illustra come:

  • Registrare un nuovo formattatore
  • Selezionare un formattatore registrato da usare
  • Implementare un formattatore personalizzato

Suggerimento

Tutto il codice sorgente di esempio di registrazione è disponibile nel browser Samples per il download. Per altre informazioni, vedere Esplorare gli esempi di codice: Registrazione in .NET.

Registrare il formattatore

Il Console provider di registrazione ha diversi formattatori predefiniti e offre la possibilità di creare un formattatore personalizzato. Per registrare uno dei formattatori disponibili, usare il metodo di estensione corrispondente Add{Type}Console :

Tipi disponibili Metodo per registrare il tipo
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

Semplice

Per usare il formattatore della Simple console, registrarlo con AddSimpleConsole:

using Microsoft.Extensions.Logging;

using ILoggerFactory loggerFactory =
    LoggerFactory.Create(builder =>
        builder.AddSimpleConsole(options =>
        {
            options.IncludeScopes = true;
            options.SingleLine = true;
            options.TimestampFormat = "HH:mm:ss ";
        }));

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
using (logger.BeginScope("[scope is enabled]"))
{
    logger.LogInformation("Hello World!");
    logger.LogInformation("Logs contain timestamp and log level.");
    logger.LogInformation("Each log message is fit in a single line.");
}

Nel codice sorgente di esempio precedente, il formattatore ConsoleFormatterNames.Simple è stato registrato. Offre ai log la possibilità non solo di incapsulare informazioni come l'ora e il livello di log in ogni messaggio, ma consente anche l'incorporamento dei colori ANSI e il rientro dei messaggi.

Quando viene eseguita questa app di esempio, i messaggi di log vengono formattati come illustrato di seguito:

Log della console di esempio scritti con il formattatore semplice.

Systemd

Logger ConsoleFormatterNames.Systemd della console:

  • Usa il formato e le severità del livello di log "Syslog"
  • Non formatta i messaggi con colori
  • Registra sempre i messaggi in una singola riga

Ciò è comunemente utile per i contenitori, che spesso usano il Systemd log della console. Con .NET 5, il logger della Simple console abilita anche una versione compatta che registra in una singola riga e consente anche di disabilitare i colori, come illustrato in un esempio precedente.

using Microsoft.Extensions.Logging;

using ILoggerFactory loggerFactory =
    LoggerFactory.Create(builder =>
        builder.AddSystemdConsole(options =>
        {
            options.IncludeScopes = true;
            options.TimestampFormat = "HH:mm:ss ";
        }));

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
using (logger.BeginScope("[scope is enabled]"))
{
    logger.LogInformation("Hello World!");
    logger.LogInformation("Logs contain timestamp and log level.");
    logger.LogInformation("Systemd console logs never provide color options.");
    logger.LogInformation("Systemd console logs always appear in a single line.");
}

L'esempio genera un output simile ai messaggi di log seguenti:

Log della console di esempio scritti con il formattatore Systemd.

Json

Per scrivere i log in un formato JSON, viene usato il Json formattatore della console. Il codice sorgente di esempio mostra come un'app ASP.NET Core potrebbe registrarla. Usando il webapp modello, creare una nuova app ASP.NET Core con il comando dotnet new :

dotnet new webapp -o Console.ExampleFormatters.Json

Quando si esegue l'app, usando il codice modello, si ottiene il formato di log predefinito seguente:

info: Console.ExampleFormatters.Json.Startup[0]
      Hello .NET friends!
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: .\snippets\logging\console-formatter-json

Per impostazione predefinita, il formattatore di log della Simple console è selezionato con la configurazione predefinita. Per modificare questa operazione, chiamando AddJsonConsole nel Program.cs:

using System.Text.Json;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.AddJsonConsole(options =>
{
    options.IncludeScopes = false;
    options.TimestampFormat = "HH:mm:ss ";
    options.JsonWriterOptions = new JsonWriterOptions
    {
        Indented = true
    };
});

using IHost host = builder.Build();

var logger =
    host.Services
        .GetRequiredService<ILoggerFactory>()
        .CreateLogger<Program>();

logger.LogInformation("Hello .NET friends!");

await host.RunAsync();

In alternativa, è anche possibile configurare questa operazione usando la configurazione di registrazione, ad esempio quella presente nel file appsettings.json :

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        },
        "Console": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            },
            "FormatterName": "json",
            "FormatterOptions": {
                "SingleLine": true,
                "IncludeScopes": true,
                "TimestampFormat": "HH:mm:ss ",
                "UseUtcTimestamp": true,
                "JsonWriterOptions": {
                    "Indented": true
                }
            }
        }
    },
    "AllowedHosts": "*"
}

Eseguire di nuovo l'app, con la modifica precedente, il messaggio di log è ora formattato come JSON:

{
  "Timestamp": "02:28:19 ",
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Console.ExampleFormatters.Json.Startup",
  "Message": "Hello .NET friends!",
  "State": {
    "Message": "Hello .NET friends!",
    "{OriginalFormat}": "Hello .NET friends!"
  }
}
{
  "Timestamp": "02:28:21 ",
  "EventId": 14,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Now listening on: https://localhost:5001",
  "State": {
    "Message": "Now listening on: https://localhost:5001",
    "address": "https://localhost:5001",
    "{OriginalFormat}": "Now listening on: {address}"
  }
}
{
  "Timestamp": "02:28:21 ",
  "EventId": 14,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Now listening on: http://localhost:5000",
  "State": {
    "Message": "Now listening on: http://localhost:5000",
    "address": "http://localhost:5000",
    "{OriginalFormat}": "Now listening on: {address}"
  }
}
{
  "Timestamp": "02:28:21 ",
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Application started. Press Ctrl\u002BC to shut down.",
  "State": {
    "Message": "Application started. Press Ctrl\u002BC to shut down.",
    "{OriginalFormat}": "Application started. Press Ctrl\u002BC to shut down."
  }
}
{
  "Timestamp": "02:28:21 ",
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Hosting environment: Development",
  "State": {
    "Message": "Hosting environment: Development",
    "envName": "Development",
    "{OriginalFormat}": "Hosting environment: {envName}"
  }
}
{
  "Timestamp": "02:28:21 ",
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Content root path: .\\snippets\\logging\\console-formatter-json",
  "State": {
    "Message": "Content root path: .\\snippets\\logging\\console-formatter-json",
    "contentRoot": ".\\snippets\\logging\\console-formatter-json",
    "{OriginalFormat}": "Content root path: {contentRoot}"
  }
}

Suggerimento

Per impostazione predefinita, il Json formattatore della console registra ogni messaggio in una singola riga. Per renderlo più leggibile durante la configurazione del formattatore, impostare JsonWriterOptions.Indented su true.

Attenzione

Quando si usa il formattatore della console Json, non passare messaggi di log già serializzati come JSON. L'infrastruttura di registrazione stessa gestisce già la serializzazione dei messaggi di log, quindi se si passa un messaggio di log già serializzato, verrà serializzato doppio, causando così un output in formato non valido.

Imposta il formattatore con la configurazione

Gli esempi precedenti hanno illustrato come registrare un formattatore a livello di codice. In alternativa, questa operazione può essere eseguita con configurazione. Si consideri il codice sorgente dell'applicazione Web precedente, se si aggiorna il file appsettings.json anziché chiamare ConfigureLogging nel file di Program.cs , è possibile ottenere lo stesso risultato. Il file aggiornato configura il formattatore appsettings.json come segue:

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        },
        "Console": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            },
            "FormatterName": "json",
            "FormatterOptions": {
                "SingleLine": true,
                "IncludeScopes": true,
                "TimestampFormat": "HH:mm:ss ",
                "UseUtcTimestamp": true,
                "JsonWriterOptions": {
                    "Indented": true
                }
            }
        }
    },
    "AllowedHosts": "*"
}

I due valori chiave che devono essere impostati sono "FormatterName" e "FormatterOptions". Se un formattatore con il valore impostato per "FormatterName" è già registrato, tale formattatore viene selezionato e le relative proprietà possono essere configurate purché vengano fornite come chiave all'interno del "FormatterOptions" nodo. I nomi dei formattatori predefiniti sono riservati sotto ConsoleFormatterNames:

Implementare un formattatore personalizzato

Per implementare un formattatore personalizzato, è necessario:

Creare un metodo di estensione per gestirlo automaticamente:

using Microsoft.Extensions.Logging;

namespace Console.ExampleFormatters.Custom;

public static class ConsoleLoggerExtensions
{
    public static ILoggingBuilder AddCustomFormatter(
        this ILoggingBuilder builder,
        Action<CustomOptions> configure) =>
        builder.AddConsole(options => options.FormatterName = "customName")
            .AddConsoleFormatter<CustomFormatter, CustomOptions>(configure);
}

I CustomOptions sono definiti come segue:

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

public sealed class CustomOptions : ConsoleFormatterOptions
{
    public string? CustomPrefix { get; set; }
}

Nel codice precedente, le opzioni sono una sottoclasse di ConsoleFormatterOptions.

L'AddConsoleFormatter API:

  • Registra una sottoclasse di ConsoleFormatter
  • Gestisce la configurazione:
using Console.ExampleFormatters.Custom;
using Microsoft.Extensions.Logging;

using ILoggerFactory loggerFactory =
    LoggerFactory.Create(builder =>
        builder.AddCustomFormatter(options =>
            options.CustomPrefix = " ~~~~~ "));

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
using (logger.BeginScope("TODO: Add logic to enable scopes"))
{
    logger.LogInformation("Hello World!");
    logger.LogInformation("TODO: Add logic to enable timestamp and log level info.");
}

Definire una CustomFormatter sottoclasse di ConsoleFormatter:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;

namespace Console.ExampleFormatters.Custom;

public sealed class CustomFormatter : ConsoleFormatter, IDisposable
{
    private readonly IDisposable? _optionsReloadToken;
    private CustomOptions _formatterOptions;

    public CustomFormatter(IOptionsMonitor<CustomOptions> options)
        // Case insensitive
        : base("customName") =>
        (_optionsReloadToken, _formatterOptions) =
            (options.OnChange(ReloadLoggerOptions), options.CurrentValue);

    private void ReloadLoggerOptions(CustomOptions options) =>
        _formatterOptions = options;

    public override void Write<TState>(
        in LogEntry<TState> logEntry,
        IExternalScopeProvider? scopeProvider,
        TextWriter textWriter)
    {
        string? message =
            logEntry.Formatter?.Invoke(
                logEntry.State, logEntry.Exception);

        if (message is null)
        {
            return;
        }

        CustomLogicGoesHere(textWriter);
        textWriter.WriteLine(message);
    }

    private void CustomLogicGoesHere(TextWriter textWriter)
    {
        textWriter.Write(_formatterOptions.CustomPrefix);
    }

    public void Dispose() => _optionsReloadToken?.Dispose();
}

L'API precedente CustomFormatter.Write<TState> determina quale testo viene avvolto attorno a ciascun messaggio di log. Uno standard ConsoleFormatter dovrebbe essere in grado di gestire gli ambiti, i timestamp e i livelli di gravità dei log almeno a livello minimo. Inoltre, è possibile codificare i colori ANSI nei messaggi di log e specificare anche i rientri desiderati. L'implementazione di CustomFormatter.Write<TState> non dispone di queste funzionalità.

Per ispirazione sulla personalizzazione della formattazione, vedere le implementazioni esistenti nello spazio dei nomi Microsoft.Extensions.Logging.Console.

Opzioni di configurazione personalizzate

Per personalizzare ulteriormente l'estendibilità del log, è possibile configurare la classe derivata ConsoleFormatterOptions tramite qualsiasi provider di configurazione. Ad esempio, è possibile usare il provider di configurazione JSON per definire le opzioni personalizzate. Definire prima di tutto la sottoclasse ConsoleFormatterOptions .

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.CustomWithConfig;

public sealed class CustomWrappingConsoleFormatterOptions : ConsoleFormatterOptions
{
    public string? CustomPrefix { get; set; }

    public string? CustomSuffix { get; set; }
}

La classe di opzioni del formattatore della console precedente definisce due proprietà personalizzate, che rappresentano un prefisso e un suffisso. Definire quindi il file appsettings.json che configurerà le opzioni del formattatore della console.

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        },
        "Console": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            },
            "FormatterName": "CustomTimePrefixingFormatter",
            "FormatterOptions": {
                "CustomPrefix": "|-<[",
                "CustomSuffix": "]>-|",
                "SingleLine": true,
                "IncludeScopes": true,
                "TimestampFormat": "HH:mm:ss.ffff ",
                "UseUtcTimestamp": true,
                "JsonWriterOptions": {
                    "Indented": true
                }
            }
        }
    },
    "AllowedHosts": "*"
}

Nel file di configurazione JSON precedente:

  • Il "Logging" nodo definisce un oggetto "Console".
  • Il "Console" nodo specifica un "FormatterName" di "CustomTimePrefixingFormatter", che viene associato a un formattatore personalizzato.
  • Il "FormatterOptions" nodo definisce un "CustomPrefix", "CustomSuffix", nonché alcune altre opzioni derivate.

Suggerimento

Il $.Logging.Console.FormatterOptions percorso JSON è riservato e verrà mappato su un oggetto personalizzato ConsoleFormatterOptions quando viene aggiunto usando il metodo di estensione AddConsoleFormatter. In questo modo è possibile definire proprietà personalizzate, oltre a quelle disponibili.

Si considerino i CustomDatePrefixingFormatterseguenti:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;

namespace Console.ExampleFormatters.CustomWithConfig;

public sealed class CustomTimePrefixingFormatter : ConsoleFormatter, IDisposable
{
    private readonly IDisposable? _optionsReloadToken;
    private CustomWrappingConsoleFormatterOptions _formatterOptions;

    public CustomTimePrefixingFormatter(
        IOptionsMonitor<CustomWrappingConsoleFormatterOptions> options)
        // Case insensitive
        : base(nameof(CustomTimePrefixingFormatter))
    {
        _optionsReloadToken = options.OnChange(ReloadLoggerOptions);
        _formatterOptions = options.CurrentValue;
    }

    private void ReloadLoggerOptions(CustomWrappingConsoleFormatterOptions options) =>
        _formatterOptions = options;

    public override void Write<TState>(
        in LogEntry<TState> logEntry,
        IExternalScopeProvider? scopeProvider,
        TextWriter textWriter)
    {
        string message =
            logEntry.Formatter(
                logEntry.State, logEntry.Exception);

        if (message == null)
        {
            return;
        }

        WritePrefix(textWriter);
        textWriter.Write(message);
        WriteSuffix(textWriter);
    }

    private void WritePrefix(TextWriter textWriter)
    {
        DateTime now = _formatterOptions.UseUtcTimestamp
            ? DateTime.UtcNow
            : DateTime.Now;

        textWriter.Write($"""
            {_formatterOptions.CustomPrefix} {now.ToString(_formatterOptions.TimestampFormat)}
            """);
    }

    private void WriteSuffix(TextWriter textWriter) =>
        textWriter.WriteLine($" {_formatterOptions.CustomSuffix}");

    public void Dispose() => _optionsReloadToken?.Dispose();
}

Nell'implementazione precedente del formattatore:

Per usare le opzioni di configurazione personalizzate, con implementazioni di formattatore personalizzate, aggiungere quando si chiama ConfigureLogging(IHostBuilder, Action<HostBuilderContext,ILoggingBuilder>).

using Console.ExampleFormatters.CustomWithConfig;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.AddConsole()
    .AddConsoleFormatter<
        CustomTimePrefixingFormatter, CustomWrappingConsoleFormatterOptions>();

using IHost host = builder.Build();

ILoggerFactory loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
ILogger<Program> logger = loggerFactory.CreateLogger<Program>();

using (logger.BeginScope("Logging scope"))
{
    logger.LogInformation("Hello World!");
    logger.LogInformation("The .NET developer community happily welcomes you.");
}

L'output della console seguente è simile a quello che potresti aspettarti dall'uso di questo CustomTimePrefixingFormatter.

|-<[ 15:03:15.6179 Hello World! ]>-|
|-<[ 15:03:15.6347 The .NET developer community happily welcomes you. ]>-|

Implementare la formattazione personalizzata dei colori

Per abilitare correttamente le funzionalità di colore nel formattatore di registrazione personalizzato, è possibile estendere il SimpleConsoleFormatterOptions poiché ha una proprietà SimpleConsoleFormatterOptions.ColorBehavior che può essere utile per abilitare i colori nei log.

Creare un oggetto CustomColorOptions che deriva da SimpleConsoleFormatterOptions:

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

public class CustomColorOptions : SimpleConsoleFormatterOptions
{
    public string? CustomPrefix { get; set; }
}

Scrivere quindi alcuni metodi di estensione in una TextWriterExtensions classe che consentono di incorporare facilmente colori codificati ANSI all'interno di messaggi di log formattati:

namespace Console.ExampleFormatters.Custom;

public static class TextWriterExtensions
{
    const string DefaultForegroundColor = "\x1B[39m\x1B[22m";
    const string DefaultBackgroundColor = "\x1B[49m";

    public static void WriteWithColor(
        this TextWriter textWriter,
        string message,
        ConsoleColor? background,
        ConsoleColor? foreground)
    {
        // Order:
        //   1. background color
        //   2. foreground color
        //   3. message
        //   4. reset foreground color
        //   5. reset background color

        var backgroundColor = background.HasValue ? GetBackgroundColorEscapeCode(background.Value) : null;
        var foregroundColor = foreground.HasValue ? GetForegroundColorEscapeCode(foreground.Value) : null;

        if (backgroundColor != null)
        {
            textWriter.Write(backgroundColor);
        }
        if (foregroundColor != null)
        {
            textWriter.Write(foregroundColor);
        }

        textWriter.WriteLine(message);

        if (foregroundColor != null)
        {
            textWriter.Write(DefaultForegroundColor);
        }
        if (backgroundColor != null)
        {
            textWriter.Write(DefaultBackgroundColor);
        }
    }

    static string GetForegroundColorEscapeCode(ConsoleColor color) =>
        color switch
        {
            ConsoleColor.Black => "\x1B[30m",
            ConsoleColor.DarkRed => "\x1B[31m",
            ConsoleColor.DarkGreen => "\x1B[32m",
            ConsoleColor.DarkYellow => "\x1B[33m",
            ConsoleColor.DarkBlue => "\x1B[34m",
            ConsoleColor.DarkMagenta => "\x1B[35m",
            ConsoleColor.DarkCyan => "\x1B[36m",
            ConsoleColor.Gray => "\x1B[37m",
            ConsoleColor.Red => "\x1B[1m\x1B[31m",
            ConsoleColor.Green => "\x1B[1m\x1B[32m",
            ConsoleColor.Yellow => "\x1B[1m\x1B[33m",
            ConsoleColor.Blue => "\x1B[1m\x1B[34m",
            ConsoleColor.Magenta => "\x1B[1m\x1B[35m",
            ConsoleColor.Cyan => "\x1B[1m\x1B[36m",
            ConsoleColor.White => "\x1B[1m\x1B[37m",

            _ => DefaultForegroundColor
        };

    static string GetBackgroundColorEscapeCode(ConsoleColor color) =>
        color switch
        {
            ConsoleColor.Black => "\x1B[40m",
            ConsoleColor.DarkRed => "\x1B[41m",
            ConsoleColor.DarkGreen => "\x1B[42m",
            ConsoleColor.DarkYellow => "\x1B[43m",
            ConsoleColor.DarkBlue => "\x1B[44m",
            ConsoleColor.DarkMagenta => "\x1B[45m",
            ConsoleColor.DarkCyan => "\x1B[46m",
            ConsoleColor.Gray => "\x1B[47m",

            _ => DefaultBackgroundColor
        };
}

Un formattatore di colori personalizzato che gestisce l'applicazione di colori personalizzati può essere definito come segue:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;

namespace Console.ExampleFormatters.Custom;

public sealed class CustomColorFormatter : ConsoleFormatter, IDisposable
{
    private readonly IDisposable? _optionsReloadToken;
    private CustomColorOptions _formatterOptions;

    private bool ConsoleColorFormattingEnabled =>
        _formatterOptions.ColorBehavior == LoggerColorBehavior.Enabled ||
        _formatterOptions.ColorBehavior == LoggerColorBehavior.Default &&
        System.Console.IsOutputRedirected == false;

    public CustomColorFormatter(IOptionsMonitor<CustomColorOptions> options)
        // Case insensitive
        : base("customName") =>
        (_optionsReloadToken, _formatterOptions) =
            (options.OnChange(ReloadLoggerOptions), options.CurrentValue);

    private void ReloadLoggerOptions(CustomColorOptions options) =>
        _formatterOptions = options;

    public override void Write<TState>(
        in LogEntry<TState> logEntry,
        IExternalScopeProvider? scopeProvider,
        TextWriter textWriter)
    {
        if (logEntry.Exception is null)
        {
            return;
        }

        string? message =
            logEntry.Formatter?.Invoke(
                logEntry.State, logEntry.Exception);

        if (message is null)
        {
            return;
        }

        CustomLogicGoesHere(textWriter);
        textWriter.WriteLine(message);
    }

    private void CustomLogicGoesHere(TextWriter textWriter)
    {
        if (ConsoleColorFormattingEnabled)
        {
            textWriter.WriteWithColor(
                _formatterOptions.CustomPrefix ?? string.Empty,
                ConsoleColor.Black,
                ConsoleColor.Green);
        }
        else
        {
            textWriter.Write(_formatterOptions.CustomPrefix);
        }
    }

    public void Dispose() => _optionsReloadToken?.Dispose();
}

Quando si esegue l'applicazione, i log visualizzeranno il CustomPrefix messaggio nel colore verde quando FormatterOptions.ColorBehavior è Enabled.

Annotazioni

Quando LoggerColorBehavior è Disabled, i messaggi di log non interpretano i codici di colore ANSI incorporati all'interno dei messaggi di log. Vengono invece restituiti i messaggi non elaborati. Si consideri, ad esempio, quanto segue:

logger.LogInformation("Random log \x1B[42mwith green background\x1B[49m message");

Questa operazione restituirà la stringa verbatim e non è colorata.

Random log \x1B[42mwith green background\x1B[49m message

Vedere anche