Comparteix a través de


Formato de registro de la consola

En .NET 5, se ha agregado compatibilidad con el formato personalizado a los registros de la consola en el espacio de nombres Microsoft.Extensions.Logging.Console. Hay tres opciones de formato predefinidas disponibles: Simple, Systemd y Json.

Importante

Anteriormente, la enumeración ConsoleLoggerFormat permitía seleccionar el formato de registro deseado, como inteligible, que era Default, o como una sola línea, lo que también se conoce como Systemd. Sin embargo, no eran personalizables y ahora están en desuso.

En este artículo, obtendrá información sobre los formateadores de registros de la consola. En el código fuente de ejemplo se muestra cómo hacer lo siguiente:

  • Registrar un formateador nuevo
  • Seleccionar un formateador registrado para usarlo
  • Implementar un formateador personalizado

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 Examinación de ejemplos de código: registro en .NET.

Registro del formateador

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

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 posibilidad de no solo ajustar información, como el tiempo y el nivel de registro de cada mensaje de registro, sino que también permite la inserción de color ANSI y la sangría de los mensajes.

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

Registros de consola de ejemplo escritos con el formateador simple.

Systemd

Registrador de la consola ConsoleFormatterNames.Systemd:

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

Esto suele ser útil para los contenedores, que a menudo usan el registro de la consola Systemd. Con .NET 5, el registrador de la consola Simple también habilita una versión compacta que registra en una sola línea y también permite deshabilitar 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 de Systemd.

Json

Para escribir registros en formato JSON, se usa el formateador de la consola Json. El código fuente de ejemplo muestra cómo una aplicación ASP.NET Core podría realizar el registro. Con la plantilla webapp, cree una 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, obtiene 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, se selecciona el formateador de registros de la consola Simple con la configuración predeterminada. Para cambiar esto, llame a AddJsonConsole en 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 se puede configurar 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; ahora, el mensaje de registro adopta 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

De forma predeterminada, el formateador de la consola Json registra cada mensaje en una sola línea. Para mejorar la legibilidad mientras se configura el formateador, establezca JsonWriterOptions.Indented en true.

Precaución

Al usar el formateador de la consola JSON, no pase los mensajes de registro ya serializados como JSON. La propia infraestructura de registro ya administra la serialización de los mensajes de registro, por lo que si va a pasar un mensaje de registro ya serializado, se serializará doblemente, lo que provocará una salida con formato incorrecto.

Definición del formateador con configuración

En los ejemplos anteriores se ha mostrado cómo registrar un formateador mediante programación. Como alternativa, puede hacerlo con la configuración. Considere el código fuente de ejemplo de aplicación web anterior; si actualiza el archivo appsettings.json en lugar de llamar a ConfigureLogging en el archivo Program.cs, podría obtener el mismo resultado. El archivo appsettings.json actualizado configuraría el formateador como sigue:

{
    "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 se deben establecer son "FormatterName" y "FormatterOptions". Si ya está registrado un formateador con el valor establecido para "FormatterName", se selecciona ese formateador y se pueden configurar sus propiedades siempre que se proporcionen como una clave dentro del nodo "FormatterOptions". Los nombres de formateador predefinidos se reservan en ConsoleFormatterNames:

Implementar un formateador personalizado

Para implementar un formateador personalizado, debe hacer lo siguiente:

Cree un método de extensión para administrar 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);
}

Los elementos CustomOptions se definen de la manera siguiente:

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 API AddConsoleFormatter hace lo siguiente:

  • Registra una subclase de ConsoleFormatter.
  • Controla la configuración:
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 subclase CustomFormatter 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 CustomFormatter.Write<TState> anterior determina qué texto se ajusta alrededor de cada mensaje de registro. Un estándar ConsoleFormatter debe ser capaz de ajustar en torno a los ámbitos, las marcas de tiempo y el nivel de gravedad de los registros, como mínimo. Además, puede codificar los colores ANSI en los mensajes de registro y proporcionar también las sangrías deseadas. La implementación de CustomFormatter.Write<TState> carece de estas funcionalidades.

Para obtener información sobre cómo personalizar aún más el formato, vea las implementaciones existentes en el espacio de nombres Microsoft.Extensions.Logging.Console:

Opciones de configuración personalizadas

Para personalizar aún más la extensibilidad del registro, la clase ConsoleFormatterOptions derivada 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 subclase 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; }
}

En la clase de opciones del formateador de consola anterior se definen 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 nodo "Logging" define un objeto "Console".
  • El nodo "Console" especifica un objeto "FormatterName" de tipo "CustomTimePrefixingFormatter", que se asigna a un formateador personalizado.
  • El nodo "FormatterOptions" define "CustomPrefix" y "CustomSuffix", además de otras opciones derivadas.

Sugerencia

La ruta JSON $.Logging.Console.FormatterOptions está reservada y se asignará a un objeto 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 ya 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 usar opciones de configuración personalizadas, con implementaciones de formateadores personalizados, agréguelas al llamar 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 siguiente salida de la consola es similar a la que podría ver al usar este objeto 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

Con el fin de habilitar correctamente las funcionalidades de color en el formateador de registro personalizado, puede extender SimpleConsoleFormatterOptions, ya que tiene una propiedad SimpleConsoleFormatterOptions.ColorBehavior que puede ser útil para habilitar colores en los registros.

Cree un elemento CustomColorOptions derivado 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 clase TextWriterExtensions que permita la inserción conveniente de colores codificados con ANSI en los 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 mensaje CustomPrefix en color verde cuando FormatterOptions.ColorBehavior es Enabled.

Nota:

Cuando LoggerColorBehavior es Disabled, los mensajes de registro no interpretan códigos de color ANSI insertados en los mensajes de registro. En su lugar, el resultado es un mensaje sin formato. Por ejemplo, considere lo siguiente:

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

Esto generaría la cadena textual sin color.

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

Vea también