【C#】ログメッセージに変数を含める正しい方法 (Message Templates)

ILogger でログ出力を行う際、変数の値をメッセージに埋め込みたい場合、C# の文字列補間式($"")を使って結合してしまいがちです。しかし、ログのパフォーマンスや可読性、将来的な分析のしやすさを考えると、「メッセージテンプレート(Message Templates)」 を使用するのが推奨されます。

ここでは、変数を {Placeholder} 形式で埋め込む構造化ログ(Structured Logging)の書き方を解説します。

目次

実装サンプル:決済処理のログ

題材を「決済システム」とし、取引IDと金額をログに残すコードです。文字列結合ではなく、引数として変数を渡している点に注目してください。

1. PaymentWorker.cs (ログ出力クラス)

using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace PaymentApp
{
    public class PaymentWorker : BackgroundService
    {
        private readonly ILogger<PaymentWorker> _logger;

        public PaymentWorker(ILogger<PaymentWorker> logger)
        {
            _logger = logger;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // ログに出力したい変数
            var transactionId = "TX-998877";
            decimal amount = 5000m;

            // 【推奨される書き方】
            // メッセージ内に {名前} のプレースホルダーを置き、第2引数以降に変数を渡す
            _logger.LogInformation("決済処理を開始します。取引ID: {TransactionId}, 金額: {Amount}円", transactionId, amount);

            // 【非推奨の書き方】(文字列補間)
            // _logger.LogInformation($"決済処理を開始します。取引ID: {transactionId}, 金額: {amount}円");

            return Task.CompletedTask;
        }
    }
}

2. appsettings.json (ログレベル設定)

PaymentApp 名前空間の Information レベル以上のログを表示するように設定します。

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "System": "Warning",
      "Microsoft": "Warning",
      "PaymentApp": "Information"
    }
  }
}

実行結果

info: PaymentApp.PaymentWorker[0]
      決済処理を開始します。取引ID: TX-998877, 金額: 5000円

解説:なぜ $ (文字列補間) を使ってはいけないのか?

1. 構造化ログ (Structured Logging) への対応

テンプレート構文 "{Key}", value を使うと、ログ基盤(Application Insights, Elasticsearch, Seqなど)に送られた際、単なる「文章」としてだけでなく、「プロパティ(キーと値)」として保存されます。 これにより、後から「Amount が 10000 以上のログだけを検索する」といったクエリが可能になります。文字列補間($"{var}")を使ってしまうと、ただの文字列になってしまい、このメリットが失われます。

2. パフォーマンスの向上

文字列補間式($"")は、ログレベルに関係なくその場で文字列結合処理が走ります。 一方、テンプレート構文を使えば、もしそのログレベルが無効(例:Traceログだが設定はWarning以上)の場合、文字列のフォーマット処理自体がスキップされるため、無駄なCPU処理を抑えることができます。

3. 書き方のルール

  • プレースホルダーは {Name} のように名前を付けます。数字({0})も使えますが、名前付きの方が後で検索しやすくなります。
  • 引数の順番は、プレースホルダーの出現順に合わせます。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次