Mise en forme des journaux de la console

Dans .NET 5, la prise en charge de la mise en forme personnalisée a été ajoutée aux journaux de console dans l’espace de noms Microsoft.Extensions.Logging.Console. Il existe trois options de mise en forme prédéfinies disponibles : Simple, Systemd et Json.

Important

Auparavant, l’énumération ConsoleLoggerFormat permettait de sélectionner le format de journal souhaité, soit lisible par l’utilisateur, c’est-à-dire Default, soit la ligne unique, également appelée Systemd. Toutefois, ces éléments n’étaient pas personnalisables et sont désormais déconseillés.

Dans cet article, vous allez découvrir les formateurs de journal de console. L’exemple de code source montre comment :

  • Inscrire un nouveau formateur
  • Sélectionner un formateur inscrit à utiliser
  • Implémenter un formateur personnalisé

Conseil

Tous les exemples de code source de journalisation sont disponibles dans l’Explorateur d’exemples pour téléchargement. Pour plus d’informations, consultez Parcourir les exemples de code : Journalisation dans .NET.

Inscrire le formateur

Le fournisseur de journalisation Console comporte plusieurs formateurs prédéfinis et expose la possibilité de créer votre propre formateur personnalisé. Pour inscrire l’un des formateurs disponibles, utilisez la méthode d’extension Add{Type}Console correspondante :

Types disponibles Méthode pour inscrire le type
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

Simple

Pour utiliser le formateur de console Simple, inscrivez-le avec 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.");
}

Dans l’exemple de code source précédent, le formateur ConsoleFormatterNames.Simple a été inscrit. Il fournit des journaux d’activité qui permettent non seulement d’encapsuler des informations telles que le temps et le niveau de journalisation dans chaque message de journal, mais également d’intégrer les couleurs ANSI et de mettre en retrait les messages.

Lorsque cet exemple d’application est exécuté, les messages de journaux sont mis en forme comme indiqué ci-dessous :

Exemples de journaux de console écrits avec le formateur simple.

Systemd

L’enregistreur d’événements de console ConsoleFormatterNames.Systemd :

  • Utilise le format de niveau de journal et de gravités « Syslog »
  • Ne met pas en forme les messages avec des couleurs
  • Consigne toujours les messages sur une seule ligne

Cela est couramment utile pour les conteneurs, qui utilisent souvent la journalisation de la console Systemd. Avec .NET 5, l’enregistreur d’événements de console Simple active également une version compacte qui journalise dans une seule ligne et permet également de désactiver les couleurs comme indiqué dans un exemple précédent.

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’exemple produit une sortie similaire aux messages de journaux suivants :

Exemples de journaux de console écrits avec le formateur Systemd.

Json

Pour écrire des journaux au format JSON, le formateur de console Json est utilisé. L’exemple de code source montre comment une application ASP.NET Core peut l’inscrire. À l’aide du modèle webapp, créez une application ASP.NET Core avec la commande dotnet new :

dotnet new webapp -o Console.ExampleFormatters.Json

Lors de l’exécution de l’application, à l’aide du code de modèle, vous obtenez le format de journal par défaut ci-dessous :

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

Par défaut, le formateur du journal de Simple la console est sélectionné avec la configuration par défaut. Vous modifiez cela en appelant AddJsonConsole dans 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();

Vous pouvez également configurer cela à l’aide de la configuration de journalisation, telle que celle trouvée dans le fichier 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": "*"
}

Réexécutez l’application, avec la modification ci-dessus, le message de journal est désormais mis en forme au format 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}"
  }
}

Conseil

Le formateur de console Json enregistre par défaut chaque message dans une seule ligne. Pour rendre ceci plus lisible lors de la configuration du formateur, définissez la valeur JsonWriterOptions.Indented sur true.

Attention

Lorsque vous utilisez le formateur de console Json, ne transmettez pas les messages de journal qui ont déjà été sérialisés en tant que JSON. L’infrastructure de journalisation elle-même gère déjà la sérialisation des messages de journal. Par conséquent, si vous souhaitez transmettre un message de journal déjà sérialisé, il sera sérialisé en double, ce qui produit une sortie incorrecte.

Définir le formateur avec la configuration

Les exemples précédents ont montré comment inscrire un formateur par programmation. Vous pouvez également effectuer cette opération avec la configuration. Dans l’exemple de code source de l’application web précédente, si vous mettez à jour le fichier appsettings.json plutôt que d’appeler ConfigureLogging dans le fichier Program.cs, vous pouvez obtenir le même résultat. Le fichier appsettings.json mis à jour configure le formateur comme suit :

{
    "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": "*"
}

Les deux valeurs clés qui doivent être définies sont "FormatterName" et "FormatterOptions". Si un formateur dont la valeur "FormatterName" est déjà inscrite, ce formateur est sélectionné et ses propriétés peuvent être configurées tant qu’elles sont fournies en tant que clé à l’intérieur du nœud "FormatterOptions". Les noms de formateur prédéfinis sont réservés sous ConsoleFormatterNames :

Implémenter un formateur personnalisé

Pour implémenter un formateur personnalisé, vous devez :

Créez une méthode d’extension pour gérer cela pour vous :

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

Les CustomOptions sont définies comme suit :

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

Dans le code précédent, les options sont une sous-classe de ConsoleFormatterOptions.

L’API AddConsoleFormatter :

  • Inscrit une sous-classe de ConsoleFormatter
  • Gère la configuration :
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.");
}

Définir une CustomFormatter sous-classe de 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 CustomFormatter.Write<TState> précédente détermine le texte qui est encapsulé autour de chaque message de journal. La norme ConsoleFormatter doit être en mesure d’encapsuler les étendues, les horodatages et le niveau de gravité des journaux au minimum. En outre, vous pouvez encoder les couleurs ANSI dans les messages de journal et fournir également des retraits souhaités. L’implémentation des CustomFormatter.Write<TState> ne comporte pas ces fonctionnalités.

Pour plus d’inspiration sur la personnalisation de la mise en forme, consultez les implémentations existantes dans l’espace de noms Microsoft.Extensions.Logging.Console :

Options de configuration personnalisées

Pour personnaliser davantage l’extensibilité de journalisation, votre classe dérivée ConsoleFormatterOptions peut être configurée à partir de n’importe quel fournisseur de configuration. Par exemple, vous pouvez utiliser le fournisseur de configuration JSON pour définir vos options personnalisées. Commencez par définir votre sous-classe 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 d’options de formateur de console précédente définit deux propriétés personnalisées représentant un préfixe et un suffixe. Ensuite, définissez le fichier appsettings.json qui configurera vos options de formateur de 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": "*"
}

Dans le fichier de configuration JSON précédent :

  • Le nœud "Logging" définit un "Console".
  • Le nœud "Console" spécifie un "FormatterName" de "CustomTimePrefixingFormatter", qui est mappé à un formateur personnalisé.
  • Le nœud "FormatterOptions" définit un "CustomPrefix" et "CustomSuffix", ainsi que quelques autres options dérivées.

Conseil

Le chemin d’accès JSON $.Logging.Console.FormatterOptions est réservé et mappe à une valeur personnalisée ConsoleFormatterOptions lors de l’ajout à l’aide de la méthode d’extension AddConsoleFormatter. Cela permet de définir des propriétés personnalisées, en plus des propriétés disponibles.

Considérez le CustomDatePrefixingFormatter qui suit :

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

Dans l’implémentation du formateur précédent :

Pour utiliser des options de configuration personnalisées, avec des implémentations de formateur personnalisées, ajoutez lors de l’appel de 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.");
}

La sortie de la console suivante est similaire à ce que vous pourriez vous attendre à voir à partir de l’utilisation de ce CustomTimePrefixingFormatter.

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

Implémenter une mise en forme de couleur personnalisée

Pour activer correctement les fonctionnalités de couleur dans votre formateur de journalisation personnalisé, vous pouvez étendre le SimpleConsoleFormatterOptions, car il a une propriété SimpleConsoleFormatterOptions.ColorBehavior qui peut être utile pour activer les couleurs dans les journaux.

Créez un CustomColorOptions qui dérive de SimpleConsoleFormatterOptions :

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

Ensuite, écrivez certaines méthodes d’extension dans une classe TextWriterExtensions qui permettent d’incorporer facilement des couleurs codées ANSI dans les messages de journal mis en forme :

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 formateur de couleurs personnalisé qui gère l’application de couleurs personnalisées peut être défini comme suit :

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

Lorsque vous exécutez l’application, les journaux affichent le message CustomPrefix en vert de couleur lorsque FormatterOptions.ColorBehavior c’est Enabled.

Notes

Quand LoggerColorBehavior est Disabled, les messages de journal n’interprètent pas les codes de couleur ANSI incorporés dans les messages de journal. Au lieu de cela, ils génèrent le message brut. Prenons l’exemple suivant :

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

La chaîne détaillée est générée et n’est pas colorisée.

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

Voir aussi