コンソール ログの書式設定

.NET 5 では、Microsoft.Extensions.Logging.Console 名前空間のコンソール ログにカスタム書式設定のサポートが追加されました。 SimpleSystemdJson の 3 つの定義済み書式設定オプションを使用できます。

重要

それまでは、ConsoleLoggerFormat 列挙型を使用して、人間が判読できる書式設定 (こちらが Default) または Systemd とも呼ばれる単一行の、どちらか望ましいログ書式設定を選択できました。 ただし、これらはカスタマイズできず、現在は非推奨になっています。

この記事では、コンソール ログのフォーマッタについて説明します。 サンプルのソース コードでは、次の方法が示されています。

  • 新しいフォーマッタを登録する
  • 登録されているフォーマッタから使用するものを選択する
    • コードまたは構成のいずれかで
  • カスタム フォーマッタを実装する

ヒント

ログのサンプル ソース コードはすべて、サンプル ブラウザーでダウンロードできます。 詳細については、コード サンプルの参照: .NET でのログ記録に関するページをご覧ください。

フォーマッタを登録する

ログ プロバイダーにはいくつかの定義済みのフォーマッタがあり、独自のカスタム フォーマッタを作成する機能が公開されています。 使用可能ないずれかのフォーマッタを登録するには、対応する Add{Type}Console 拡張メソッドを使用します。

使用可能な種類 種類を登録するメソッド
ConsoleFormatterNames.Json ConsoleLoggerExtensions.AddJsonConsole
ConsoleFormatterNames.Simple ConsoleLoggerExtensions.AddSimpleConsole
ConsoleFormatterNames.Systemd ConsoleLoggerExtensions.AddSystemdConsole

シンプル

Simple コンソール フォーマッタを使用するには、AddSimpleConsole でそれを登録します。

using Microsoft.Extensions.Logging;

namespace Console.ExampleFormatters.Simple;

class Program
{
    static void Main()
    {
        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" ログ レベルの形式と重大度が使用されます
  • メッセージの色の書式は設定されません
  • 常に 1 行のメッセージが記録されます

これは一般にコンテナーに便利であり、通常は Systemd コンソール ログ記録が使用されます。 .NET 5 の Simple コンソール ロガーでは、単一行に記録されるコンパクト バージョンが有効になり、前のサンプルで示したように色を無効にすることもできます。

using Microsoft.Extensions.Logging;

namespace Console.ExampleFormatters.Systemd;

class Program
{
    static void Main()
    {
        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.");
        }
    }
}

Json

JSON 形式でログを書き込むには、Json コンソール フォーマッタを使用します。 サンプルのソース コードでは、ASP.NET Core アプリでそれを登録する方法が示されています。 webapp テンプレートを使用し、webapp コマンドで新しい 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 コンソール ログ フォーマッタが選択されます。 これを変更するには、AddJsonConsoleAddJsonConsole を呼び出します。

using System.Text.Json;
using Console.ExampleFormatters.Json;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(builder => builder.UseStartup<Startup>())
    .ConfigureLogging(builder =>
        builder.AddJsonConsole(options =>
        {
            options.IncludeScopes = false;
            options.TimestampFormat = "hh:mm:ss ";
            options.JsonWriterOptions = new JsonWriterOptions
            {
                Indented = true
            };
        }))
    .Build();

var logger =
    host.Services
        .GetRequiredService<ILoggerFactory>()
        .CreateLogger<Startup>();

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 コンソール フォーマッタを使用すると、各メッセージが 1 行に記録されます。 フォーマッタを構成するときにそれをさらに読みやすくするには、JsonWriterOptions.Indentedtrue に設定します。

注意事項

Json コンソール フォーマッタを使用する場合は、既に JSON としてシリアル化されているログ メッセージを渡さないでください。 ログ インフラストラクチャ自体は既にログ メッセージのシリアル化を管理しているため、既にシリアル化されているログ メッセージを渡すと、二重シリアル化され、誤った形式の出力が発生します。

構成でフォーマッタを設定する

前のサンプルには、フォーマッタをプログラムで登録する方法が示されています。 または、構成を使用してこれを行うこともできます。 前に示した Web アプリケーションのサンプル ソースコードについて考えます。Program.cs ファイルで を呼び出すのではなく、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": "*"
}

設定が必要な 2 つのキー値は、"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 class CustomOptions : ConsoleFormatterOptions
{
    public string? CustomPrefix { get; set; }
}

上記のコードでは、オプションは ConsoleFormatterOptions のサブクラスです。

AddConsoleFormatter API:

  • ConsoleFormatter のサブクラスを登録します
  • 構成を処理します。
using Microsoft.Extensions.Logging;

namespace Console.ExampleFormatters.Custom;

class Program
{
    static void Main()
    {
        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.");
        }
    }
}

ConsoleFormatterCustomerFormatter サブクラスを定義します。

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 派生クラスを、任意のConsoleFormatterOptionsから構成できます。 たとえば、JSON 構成プロバイダーを使用して、カスタム オプションを定義することができます。 最初に、ConsoleFormatterOptions サブクラスを定義します。

using Microsoft.Extensions.Logging.Console;

namespace Console.ExampleFormatters.CustomWithConfig;

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

    public string? CustomSuffix { get; set; }
}

前述のコンソール フォーマッタ オプション クラスによって、プレフィックスとサフィックスを表す 2 つのカスタム プロパティが定義されます。 次に、コンソール フォーマッタ オプションを構成する 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, _formatterOptions) =
            (options.OnChange(ReloadLoggerOptions), 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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Console.ExampleFormatters.CustomWithConfig;

class Program
{
    static void Main(string[] args)
    {
        using IHost host = Host.CreateDefaultBuilder(args)
            .ConfigureLogging(builder =>
            {
                builder.AddConsole()
                    .AddConsoleFormatter
                        <CustomTimePrefixingFormatter, CustomWrappingConsoleFormatterOptions>();
            })
            .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.ColorBehavior プロパティが含まれる SimpleConsoleFormatterOptions を拡張できます。

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 の色コードは、ログ メッセージによって解釈 "LoggerColorBehavior"。 代わりに、生のメッセージが出力されます。 たとえば、次のことを考慮してください。

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

これにより逐語的文字列が出力され、色分けされ "ません"。

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

関連項目