Freigeben über


Formatieren von Konsolenprotokollen

In .NET 5 wurde unterstützung für benutzerdefinierte Formatierungen zu Konsolenprotokollen im Microsoft.Extensions.Logging.Console Namespace hinzugefügt. Es stehen drei vordefinierte Formatierungsoptionen zur Verfügung: Simple, , Systemdund Json.

Von Bedeutung

Zuvor konnte das ConsoleLoggerFormat-Enum verwendet werden, um das gewünschte Protokollformat auszuwählen, entweder menschenlesbar, was das Default ist, oder eine einzelne Zeile, die auch als Systemd bekannt ist. Diese waren jedoch nicht anpassbar und sind jetzt veraltet.

In diesem Artikel erfahren Sie mehr über Konsolenprotokollformatierer. Der Beispielquellcode veranschaulicht folgendes:

  • Registrieren Sie einen neuen Formatierer
  • Wählen Sie einen registrierten Formatierer zur Verwendung aus.
  • Implementieren eines benutzerdefinierten Formatierers

Tipp

Der gesamte Quellcode des Protokollierungsbeispiels steht im Beispielbrowser zum Download zur Verfügung. Weitere Informationen finden Sie unter Durchsuchen von Codebeispielen: Protokollierung in .NET.

Registrieren eines Formatierers

Der Console Protokollierungsanbieter verfügt über mehrere vordefinierte Formatierer und macht die Möglichkeit verfügbar, einen eigenen benutzerdefinierten Formatierer zu erstellen. Verwenden Sie die entsprechende Add{Type}Console Erweiterungsmethode, um einen der verfügbaren Formatierer zu registrieren:

Verfügbare Typen Methode zum Registrieren des Typs
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

Einfach

Um den Simple Konsolenformatierer zu verwenden, registrieren Sie ihn bei 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.");
}

Im vorangehenden Beispielquellcode wurde der Formatierer ConsoleFormatterNames.Simple registriert. Er bietet für Protokolle nicht nur die Möglichkeit, Informationen wie z. B. Zeit und Protokollgrad in jeder Protokollmeldung zu umschließen, sondern ermöglicht auch die Einbettung von ANSI-Farben und Einzüge für Meldungen.

Wenn diese Beispiel-App ausgeführt wird, werden die Protokollmeldungen wie unten dargestellt formatiert:

Beispielkonsolenprotokolle, die mit dem einfachen Formatierer geschrieben wurden.

Systemd

Der ConsoleFormatterNames.Systemd Konsolenprotokollierer:

  • Sie verwendet das Protokolliergradformat und die Schweregrade von Syslog.
  • Formatiert keine Nachrichten mit Farben.
  • Protokolliert immer Nachrichten in einer einzelnen Zeile.

Dies ist häufig nützlich für Container, die häufig die Systemd Konsolenprotokollierung verwenden. Mit .NET 5 ermöglicht der Simple Konsolenprotokollierer auch eine kompakte Version, die sich in einer einzelnen Zeile anmeldet, und ermöglicht außerdem das Deaktivieren von Farben, wie in einem früheren Beispiel gezeigt.

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

Das Beispiel erzeugt eine Ausgabe ähnlich wie die folgenden Protokollmeldungen:

Beispielkonsolenprotokolle, die mit dem Systemd-Formatierer geschrieben wurden.

Json

Zum Schreiben von Protokollen in einem JSON-Format wird der Json Konsolenformatierer verwendet. Der Beispielquellcode zeigt, wie eine ASP.NET Core-App sie möglicherweise registriert. Erstellen Sie mithilfe der webapp Vorlage eine neue ASP.NET Core-App mit dem neuen Befehl dotnet :

dotnet new webapp -o Console.ExampleFormatters.Json

Wenn Sie die App mit dem Vorlagencode ausführen, erhalten Sie das folgende Standardprotokollformat:

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

Standardmäßig ist der Simple Konsolenprotokollformatierer mit Standardkonfiguration ausgewählt. Sie ändern dies durch Aufrufen AddJsonConsole der 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();

Alternativ können Sie dies auch mithilfe der Protokollierungskonfiguration konfigurieren, z. B. die in der appsettings.json Datei enthalten ist:

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

Führen Sie die App mit der oben genannten Änderung erneut aus, die Protokollnachricht ist jetzt als JSON formatiert.

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

Tipp

Der Json Konsolenformatierer protokolliert standardmäßig jede Nachricht in einer einzelnen Zeile. Um die Lesbarkeit beim Konfigurieren des Formatierers zu verbessern, legen Sie die JsonWriterOptions.Indented Einstellung auf true.

Vorsicht

Wenn Sie den Json-Konsolenformatierer verwenden, übergeben Sie keine Protokollmeldungen, die bereits als JSON serialisiert wurden. Die Protokollierungsinfrastruktur selbst verwaltet bereits die Serialisierung von Protokollnachrichten. Wenn Sie also eine bereits serialisierte Protokollnachricht übergeben möchten, wird sie doppelt serialisiert, wodurch die falsch formatierte Ausgabe verursacht wird.

Einstellen des Formatierers durch Konfiguration

In den vorherigen Beispielen wurde gezeigt, wie ein Formatierer programmatisch registriert werden kann. Alternativ lässt sich dies über die Konfiguration erledigen. Berücksichtigen Sie den vorherigen Quellcode der Webanwendung, wenn Sie die appsettings.json Datei aktualisieren und nicht in der ConfigureLogging Datei aufrufen, könnten Sie dasselbe Ergebnis erzielen. Die aktualisierte appsettings.json Datei würde den Formatierer wie folgt konfigurieren:

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

Die beiden Schlüsselwerte, die festgelegt werden müssen, sind "FormatterName" und "FormatterOptions". Wenn ein Formatierer mit dem festgelegten "FormatterName" Wert bereits registriert ist, wird dieser Formatierer ausgewählt, und seine Eigenschaften können so konfiguriert werden, dass sie als Schlüssel innerhalb des "FormatterOptions" Knotens bereitgestellt werden. Die vordefinierten Formatierernamen sind unter ConsoleFormatterNames reserviert:

Implementieren eines benutzerdefinierten Formatierers

Um einen benutzerdefinierten Formatierer zu implementieren, müssen Sie:

Erstellen Sie eine Erweiterungsmethode, um dies für Sie zu behandeln:

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

Dies CustomOptions ist wie folgt definiert:

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

Im vorherigen Code sind die Optionen eine Unterklasse von ConsoleFormatterOptions.

Die AddConsoleFormatter API:

  • Registriert eine Unterklasse von ConsoleFormatter
  • Sie übernimmt die Konfiguration:
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.");
}

Definieren einer CustomFormatter Unterklasse von 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();
}

Die vorangehende CustomFormatter.Write<TState> API legt fest, welcher Text jede Protokollnachricht einrahmt. Ein Standard-ConsoleFormatter sollte zumindest Bereiche, Zeitstempel und den Schweregrad von Protokollen umschließen können. Darüber hinaus können Sie ANSI-Farben in den Protokollmeldungen codieren und auch gewünschte Einzüge bereitstellen. Die Implementierung der CustomFormatter.Write<TState> weist diese Fähigkeiten nicht auf.

Inspiration zur weiteren Anpassung der Formatierung finden Sie in den vorhandenen Implementierungen im Microsoft.Extensions.Logging.Console Namespace:

Benutzerdefinierte Konfigurationsoptionen

Um die Protokollierungserweiterung weiter anzupassen, kann Ihre abgeleitete ConsoleFormatterOptions Klasse von jedem Konfigurationsanbieter konfiguriert werden. Sie können beispielsweise den JSON-Konfigurationsanbieter verwenden, um Ihre benutzerdefinierten Optionen zu definieren. Definieren Sie zuerst Ihre ConsoleFormatterOptions Unterklasse.

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.CustomWithConfig;

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

    public string? CustomSuffix { get; set; }
}

Die obige Konsolenformatieroptionenklasse definiert zwei benutzerdefinierte Eigenschaften, die ein Präfix und Suffix darstellen. Definieren Sie als Nächstes die appsettings.json Datei, die die Optionen für die Konsolenformatierung konfiguriert.

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

In der vorherigen JSON-Konfigurationsdatei:

  • Der "Logging" Knoten definiert ein "Console".
  • Der "Console"-Knoten gibt ein "FormatterName"-Objekt von "CustomTimePrefixingFormatter" an, das einem benutzerdefinierten Formatierer zugeordnet wird.
  • Der "FormatterOptions" Knoten definiert ein "CustomPrefix", und "CustomSuffix", sowie einige andere abgeleitete Optionen.

Tipp

Der $.Logging.Console.FormatterOptions JSON-Pfad ist reserviert und wird einer benutzerdefinierten ConsoleFormatterOptions Zuordnung zugeordnet, wenn sie mithilfe der AddConsoleFormatter Erweiterungsmethode hinzugefügt wird. Dies bietet die Möglichkeit, benutzerdefinierte Eigenschaften zusätzlich zu den verfügbaren eigenschaften zu definieren.

Beachten Sie Folgendes CustomDatePrefixingFormatter:

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

In der oben stehenden Formatierungsimplementierung ist Folgendes passiert:

  • Das CustomWrappingConsoleFormatterOptions-Objekt wird auf Änderungen überwacht und entsprechend aktualisiert.
  • Geschriebene Nachrichten werden mit dem konfigurierten Präfix und Suffix umschlossen.
  • Ein Zeitstempel wird nach dem Präfix, aber vor der Nachricht hinzugefügt, wobei die konfigurierten ConsoleFormatterOptions.UseUtcTimestamp und ConsoleFormatterOptions.TimestampFormat Werte verwendet werden.

Fügen Sie beim Aufrufen von ConfigureLogging(IHostBuilder, Action<HostBuilderContext,ILoggingBuilder>) hinzu, um benutzerdefinierte Konfigurationsoptionen mit benutzerdefinierten Formatiererimplementierungen zu verwenden.

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

Die folgende Konsolenausgabe ähnelt dem, was Sie erwarten könnten, wenn Sie CustomTimePrefixingFormatter verwenden.

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

Implementieren von benutzerdefinierter Farbformatierung

Um Farbfunktionen im benutzerdefinierten Protokollierungsformatierer ordnungsgemäß zu aktivieren, können Sie SimpleConsoleFormatterOptions erweitern, da es die SimpleConsoleFormatterOptions.ColorBehavior-Eigenschaft hat, die nützlich sein kann, um Farben in Protokollen zu aktivieren.

Erstellen Sie ein CustomColorOptions, das von SimpleConsoleFormatterOptions abgeleitet ist.

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

Schreiben Sie als Nächstes einige Erweiterungsmethoden in eine TextWriterExtensions Klasse, mit der ANSI-codierte Farben bequem in formatierte Protokollmeldungen eingebettet werden können:

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

Ein benutzerdefinierter Farbformatierer, der das Anwenden benutzerdefinierter Farben behandelt, kann wie folgt definiert werden:

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

Wenn Sie die Anwendung ausführen, wird in den Protokollen die CustomPrefix Meldung in der Farbe Grün angezeigt, wenn FormatterOptions.ColorBehaviorEnabled ist.

Hinweis

Wenn LoggerColorBehavior auf Disabled festgelegt ist, werden keine eingebetteten ANSI-Farbcodes in Protokollmeldungen interpretiert. Stattdessen geben sie die unformatierte Nachricht aus. Betrachten Sie beispielsweise Folgendes:

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

Hierdurch wird die ausführliche Zeichenfolge ohne Farbformatierung ausgegeben.

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

Siehe auch