Compartir vía


Formato de registro de la consola

El Microsoft.Extensions.Logging.Console espacio de nombres proporciona soporte para el formato personalizado en los registros de consola. Hay tres opciones de formato predefinidas disponibles: Simple, Systemdy Json.

Importante

Antes de .NET 5, la ConsoleLoggerFormat enumeración permitía seleccionar el formato de registro deseado, ya sea legible por humanos, que era la Default, o una sola línea, que también se conoce como Systemd. Sin embargo, estos no eran personalizables y ahora están en desuso.

En este artículo, obtendrá información sobre los formateadores de registro de consola. El código fuente de ejemplo muestra cómo:

  • Registre un nuevo formateador.
  • Seleccione un formateador registrado que se va a usar, ya sea mediante código o configuración.
  • Implemente un formateador personalizado. Actualizas la configuración a través de IOptionsMonitor<TOptions> y habilitas el formato de colores personalizados.

Sugerencia

Todo el código fuente del ejemplo de registro está disponible en el Explorador de ejemplos para su descarga. Para obtener más información, consulte Explorar ejemplos de código: registro en .NET.

Formateador de registros

El Console proveedor de registro tiene varios formateadores predefinidos y ofrece la posibilidad de crear tu propio formateador personalizado. Para registrar cualquiera de los formateadores disponibles, use el método de extensión correspondiente Add{Type}Console :

Tipos disponibles Método para registrar el tipo
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

Simple

Para usar el formateador de consola Simple, regístrelo 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.");
}

En el código fuente de ejemplo anterior se registró el formateador ConsoleFormatterNames.Simple. Proporciona registros con la capacidad de no solo encapsular información como el tiempo y el nivel de registro en cada mensaje de registro, sino que también permite la inserción de colores ANSI y la sangría de mensajes.

Cuando se ejecuta esta aplicación de ejemplo, los mensajes de registro tienen el formato siguiente:

Registros de consola de ejemplo escritos con el formateador simple.

Systemd

El registrador de consola ConsoleFormatterNames.Systemd

  • Usa el formato de nivel de registro "Syslog" y los niveles de severidad.
  • No da formato a los mensajes con colores.
  • Registra siempre los mensajes en una sola línea.

Esto suele ser útil para los contenedores, que a menudo usan el registro de la consola Systemd. El Simple registrador de consola también habilita una versión compacta que registra en una sola línea y también permite deshabilitar los colores como se muestra en un ejemplo anterior.

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

En el ejemplo se genera una salida similar a los siguientes mensajes de registro:

Registros de consola de ejemplo escritos con el formateador systemd.

Json

Para escribir registros en un formato JSON, se usa el Json formateador de consola. El código fuente de ejemplo muestra cómo una aplicación ASP.NET Core puede registrarla. Con la webapp plantilla, cree una nueva aplicación ASP.NET Core con el comando dotnet new :

dotnet new webapp -o Console.ExampleFormatters.Json

Al ejecutar la aplicación, con el código de plantilla, obtendrá el formato de registro predeterminado siguiente:

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

De forma predeterminada, el Simple formateador de registro de consola está seleccionado con la configuración predeterminada. Para cambiarlo, llame a AddJsonConsole en el 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();

Como alternativa, también puede configurarlo mediante la configuración de registro, como la que se encuentra en el archivo 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": "*"
}

Vuelva a ejecutar la aplicación, con el cambio anterior, el mensaje de registro ahora tiene el formato 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}"
  }
}

Sugerencia

El Json formateador de consola, de forma predeterminada, registra cada mensaje en una sola línea. Para que sea más legible al configurar el formateador, establezca JsonWriterOptions.Indented en true.

Precaución

Al usar el formateador de consola JSON, no pase mensajes de registro que ya se hayan serializado como JSON. La propia infraestructura de registro administra la serialización de mensajes de registro. Por lo tanto, si pasa un mensaje de registro que ya está serializado, se serializará dos veces, lo que provocará una salida malformada.

Establecimiento del formateador con configuración

Los ejemplos anteriores mostraron cómo registrar un formateador de forma programática. Como alternativa, esto se puede hacer con la configuración. Tenga en cuenta el código fuente de ejemplo de aplicación web anterior, si actualiza el archivo appsettings.json en lugar de llamar ConfigureLogging al archivo Program.cs , podría obtener el mismo resultado. El archivo actualizado appsettings.json configuraría el formateador de la siguiente manera:

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

Los dos valores de clave que deben establecerse son "FormatterName" y "FormatterOptions". Si un formateador con el valor establecido para "FormatterName" ya está registrado, se selecciona ese formateador y sus propiedades se pueden configurar siempre y cuando se proporcionen como una clave dentro del "FormatterOptions" nodo. Los nombres de formateador predefinidos están reservados en ConsoleFormatterNames:

Implementación de un formateador personalizado

Para implementar un formateador personalizado, debe:

Cree un método de extensión para controlar esto automáticamente:

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

CustomOptions Se definen de la siguiente manera:

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

En el código anterior, las opciones son una subclase de ConsoleFormatterOptions.

La AddConsoleFormatter API:

  • Registra una subclase de ConsoleFormatter.
  • Gestiona la configuración. Usa un token de cambio para sincronizar las actualizaciones, en función del patrón de opciones y la interfaz IOptionsMonitor .
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.");
}

Defina una CustomFormatter subclase 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();
}

La API anterior CustomFormatter.Write<TState> determina qué texto rodea cada mensaje de registro. Como mínimo, un estándar ConsoleFormatter debería poder abarcar los ámbitos, las marcas de tiempo y el nivel de severidad de los registros. Además, puede codificar colores ANSI en los mensajes de registro y proporcionar también indentaciones deseadas. La implementación de CustomFormatter.Write<TState> carece de estas funcionalidades.

Para obtener inspiración sobre la personalización adicional del formato, consulte las implementaciones existentes en el Microsoft.Extensions.Logging.Console espacio de nombres:

Opciones de configuración personalizadas

Para personalizar aún más la extensibilidad del registro, la clase derivada ConsoleFormatterOptions se puede configurar desde cualquier proveedor de configuración. Por ejemplo, podría usar el proveedor de configuración JSON para definir las opciones personalizadas. En primer lugar, defina la ConsoleFormatterOptions subclase.

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 clase de opciones de formateador de consola anterior define dos propiedades personalizadas, que representan un prefijo y un sufijo. A continuación, defina el archivo appsettings.json que configurará las opciones del formateador de consola.

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

En el archivo de configuración JSON anterior:

  • El "Logging" nodo define un "Console".
  • El "Console" nodo especifica un "FormatterName" de "CustomTimePrefixingFormatter", que se correlaciona con un formateador personalizado.
  • El "FormatterOptions" nodo define un "CustomPrefix", y "CustomSuffix", así como otras opciones derivadas.

Sugerencia

La $.Logging.Console.FormatterOptions ruta de acceso JSON está reservada y se asignará a un ConsoleFormatterOptions personalizado cuando se agregue mediante el método de extensión AddConsoleFormatter. Esto proporciona la capacidad de definir propiedades personalizadas, además de las disponibles.

Observe la sintaxis CustomDatePrefixingFormatter siguiente:

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

En la implementación del formateador anterior:

Para utilizar opciones de configuración personalizadas, con implementaciones de formateador personalizadas, añádalo al realizar la llamada a 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 salida de consola que verá a continuación es similar a la que podría esperar encontrarse al usar este CustomTimePrefixingFormatter.

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

Implementación del formato de color personalizado

Para habilitar correctamente las funcionalidades de color en su formateador de registro personalizado, puede ampliar el SimpleConsoleFormatterOptions ya que tiene la propiedad SimpleConsoleFormatterOptions.ColorBehavior que puede ser útil para habilitar los colores en los registros.

Cree un CustomColorOptions que derive de SimpleConsoleFormatterOptions:

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

A continuación, escriba algunos métodos de extensión en una TextWriterExtensions clase que permita insertar convenientemente colores codificados ANSI en mensajes de registro con formato:

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 formateador de color personalizado que controla la aplicación de colores personalizados podría definirse de la siguiente manera:

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

Al ejecutar la aplicación, los registros mostrarán el CustomPrefix mensaje en el color verde cuando FormatterOptions.ColorBehavior sea Enabled.

Nota:

Cuando LoggerColorBehavior es Disabled, los mensajes de registro no interpretan los códigos de color ANSI incrustados dentro de los mensajes de registro. En su lugar, generan el mensaje sin procesar. Por ejemplo, tenga en cuenta lo siguiente:

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

Esto generaría la cadena literal, y no está coloreada.

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

Consulte también