다음을 통해 공유


콘솔 로그 서식 지정

.NET 5에서 Microsoft.Extensions.Logging.Console 네임스페이스의 콘솔 로그에 사용자 지정 서식에 대한 지원이 추가되었습니다. 세 가지 서식 옵션 Simple, SystemdJson이 미리 정의되어 있습니다.

Important

이전에는 ConsoleLoggerFormat 열거형에서 사람이 읽을 수 있는 로그 형식(Default) 또는 한 줄 로그 형식(Systemd라고도 함)에서 원하는 대로 선택할 수 있었습니다. 그러나 이러한 로그 형식은 사용자 지정이 불가능했으며 이제는 사용되지 않습니다.

이 문서에서는 콘솔 로그 포맷터에 대해 알아봅니다. 샘플 소스 코드에서는 다음 작업을 수행하는 방법을 보여 줍니다.

  • 새 포맷터를 등록
  • 사용할 등록된 포맷터를 선택
    • 코드 또는 구성을 통해
  • 사용자 지정 포맷터를 구현

모든 로깅 예제 소스 코드는 샘플 브라우저에서 다운로드할 수 있습니다. 자세한 내용은 코드 샘플 찾아보기: .NET의 로깅을 참조하세요.

포맷터 등록

Console 로깅 공급자는 미리 정의된 포맷터를 여러 개 포함하고 사용자 지정 포맷터를 작성하는 기능을 제공합니다. 사용 가능한 포맷터를 등록하려면 해당 Add{Type}Console 확장 메서드를 사용합니다.

사용 가능한 형식 형식을 등록하는 메서드
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

단순

Simple 콘솔 포맷터를 사용하려면 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.");
}

위의 샘플 소스 코드에서는 ConsoleFormatterNames.Simple 포맷터가 등록되었습니다. 이 포맷터는 각 로그 메시지에 시간 및 로그 수준과 같은 정보를 래핑할 수 있는 기능을 제공하지만, ANSI 색 포함 및 메시지 들여쓰기도 허용합니다.

이 샘플 앱이 실행되면 로그 메시지의 형식은 아래와 같습니다.

간단한 포맷터를 사용하여 작성된 콘솔 로그의 예입니다.

Systemd

ConsoleFormatterNames.Systemd 콘솔 로거:

  • ‘Syslog’ 로그 수준 형식 및 심각도를 사용합니다.
  • 색을 사용한 메시지 서식 지정을 제공하지 않습니다.
  • 메시지를 항상 한 줄로 기록합니다.

Systemd 콘솔 로깅을 흔히 사용하는 컨테이너에 유용합니다. .NET 5에서는 Simple 콘솔 로거를 사용하여 한 줄로 로깅하는 압축 버전을 사용할 수도 있으며, 이전 샘플에 표시된 대로 색을 사용하지 않도록 설정할 수도 있습니다.

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

이 예에서는 다음 로그 메시지와 유사한 출력을 생성합니다.

Systemd 포맷터를 사용하여 작성된 콘솔 로그의 예입니다.

Json

JSON 형식으로 로그를 작성하려면 Json 콘솔 포맷터가 사용됩니다. 샘플 소스 코드에서는 ASP.NET Core 앱에서 이 포맷터를 등록하는 방법을 보여 줍니다. webapp 템플릿을 사용하여 dotnet new 명령으로 새 ASP.NET Core 앱을 만듭니다.

dotnet new webapp -o Console.ExampleFormatters.Json

앱이 실행되는 동안 템플릿 코드를 사용하여 아래 기본 로그 형식을 가져옵니다.

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

기본적으로 Simple 콘솔 로그 포맷터는 기본 구성으로 선택됩니다. Program.cs에서 AddJsonConsole을 호출하여 이를 변경합니다.

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

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

위의 변경 내용으로 앱을 다시 실행합니다. 이제 로그 메시지는 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}"
  }
}

Json 콘솔 포맷터는 기본적으로 각 메시지를 한 줄에 기록합니다. 포맷터를 구성하는 동안 보다 읽기 쉽게 만들려면 JsonWriterOptions.Indentedtrue로 설정합니다.

주의

Json 콘솔 포맷터를 사용할 때 이미 JSON으로 직렬화된 로그 메시지를 전달하지 마세요. 로깅 인프라 자체는 이미 로그 메시지의 직렬화를 관리하므로 이미 직렬화된 로그 메시지를 전달하는 경우 이중 직렬화되어 잘못된 형식의 출력이 발생합니다.

구성을 사용하여 포맷터 설정

이전 샘플에서는 프로그래밍 방식으로 포맷터를 등록하는 방법을 보여 주었습니다. 구성을 사용하여 이 작업을 수행할 수도 있습니다. 이전 웹 애플리케이션 샘플 소스 코드를 생각해 보세요. Program.cs 파일에서 ConfigureLogging을 호출하는 대신 appsettings.json 파일을 업데이트하면 동일한 결과를 얻을 수 있습니다. 업데이트된 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": "*"
}

설정해야 하는 두 가지 키 값은 "FormatterName""FormatterOptions"입니다. "FormatterName"에 대한 값이 설정된 포맷터가 이미 등록되어 있으면 해당 포맷터가 선택되고 "FormatterOptions" 노드 내에서 키로 제공되는 경우에 한해 해당 속성을 구성할 수 있습니다. 미리 정의된 포맷터 이름은 ConsoleFormatterNames에 예약됩니다.

사용자 지정 포맷터를 구현

사용자 지정 포맷터를 구현하려면 다음 작업을 수행해야 합니다.

이를 처리하는 확장 메서드를 만듭니다.

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는 아래와 같이 정의됩니다.

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

위의 코드에서 옵션은 ConsoleFormatterOptions의 하위 클래스입니다.

AddConsoleFormatter API:

  • ConsoleFormatter의 하위 클래스를 등록합니다.
  • 다음과 같이 구성을 처리합니다.
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.");
}

ConsoleFormatterCustomFormatter 하위 클래스를 정의합니다.

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

위의 CustomFormatter.Write<TState> API는 각 로그 메시지 주위에 래핑되는 텍스트를 지정합니다. 표준 ConsoleFormatter에서는 적어도 로그의 범위, 타임스탬프 및 심각도 수준을 래핑할 수 있어야 합니다. 또한 로그 메시지의 ANSI 색을 인코딩하고 원하는 들여쓰기도 제공할 수 있습니다. CustomFormatter.Write<TState>의 구현에는 이러한 기능이 없습니다.

서식을 추가로 사용자 지정하는 방법에 대한 자세한 내용은 Microsoft.Extensions.Logging.Console 네임스페이스의 기존 구현을 참조하세요.

사용자 지정 구성 옵션

로깅 확장성을 추가로 사용자 지정하기 위해 모든 구성 공급자에서 파생 ConsoleFormatterOptions 클래스를 구성할 수 있습니다. 예를 들어 JSON 구성 공급자를 사용하여 사용자 지정 옵션을 정의할 수 있습니다. 먼저 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; }
}

위의 콘솔 포맷터 옵션 클래스는 접두사와 접미사를 나타내는 두 개의 사용자 지정 속성을 정의합니다. 다음으로, 콘솔 포맷터 옵션을 구성하는 appsettings.json 파일을 정의합니다.

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

위의 JSON 구성 파일에서:

  • "Logging" 노드는 "Console"을 정의합니다.
  • "Console" 노드는 사용자 지정 포맷터에 매핑되는 "CustomTimePrefixingFormatter""FormatterName"을 지정합니다.
  • "FormatterOptions" 노드는 "CustomPrefix""CustomSuffix"와 몇 가지 다른 파생된 옵션을 정의합니다.

$.Logging.Console.FormatterOptions JSON 경로는 예약되어 있으며, AddConsoleFormatter 확장 메서드를 사용하여 추가되면 사용자 지정 ConsoleFormatterOptions에 매핑됩니다. 그러면 사용 가능한 사용자 지정 속성 외에 사용자 지정 속성을 정의할 수 있습니다.

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

위의 포맷터 구현에서:

  • CustomWrappingConsoleFormatterOptions는 변경 내용이 있는지 모니터링되고 적절하게 업데이트됩니다.
  • 작성된 메시지는 구성된 접두사 및 접미사로 래핑됩니다.
  • 타임스탬프가 구성된 ConsoleFormatterOptions.UseUtcTimestampConsoleFormatterOptions.TimestampFormat 값을 사용하여 접두사 뒤와 메시지 앞 사이에 추가됩니다.

사용자 지정 포맷터 구현에서 사용자 지정 구성 옵션을 사용하려면 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.");
}

다음 콘솔 출력은 이 CustomTimePrefixingFormatter를 사용하여 볼 수 있는 출력과 유사합니다.

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

사용자 지정 색 서식 구현

사용자 지정 로깅 포맷터에서 색 기능을 제대로 사용하려면 SimpleConsoleFormatterOptions를 확장할 수 있습니다. 로그에서 색을 사용하도록 설정하는 데 유용할 수 있는 SimpleConsoleFormatterOptions.ColorBehavior 속성이 있기 때문입니다.

SimpleConsoleFormatterOptions에서 파생되는 CustomColorOptions를 만듭니다.

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.Custom;

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

다음으로, TextWriterExtensions 클래스에서 서식 지정된 로그 메시지 내에 ANSI 코딩된 색을 편리하게 포함할 수 있도록 하는 몇몇 확장 메서드를 작성합니다.

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

사용자 지정 색 적용을 처리하는 사용자 지정 색 포맷터는 다음과 같이 정의할 수 있습니다.

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

애플리케이션을 실행할 때 FormatterOptions.ColorBehaviorEnabled인 경우 로그에서 CustomPrefix 메시지가 녹색으로 표시됩니다.

참고 항목

LoggerColorBehaviorDisabled이면 로그 메시지는 로그 메시지에 포함된 ANSI 색 코드를 해석하지 ‘않습니다’. 대신 원시 메시지를 출력합니다. 다음 예를 살펴보세요.

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

축자 문자열이 출력되고 색이 지정되지 ‘않습니다’.

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

참고 항목