はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】どうやらMicrosoft.Extensons.LoggingはMessageTemplateのIndexによる順序の制御に対応していないらしい

はじめに

Microsoft.Extensions.LoggingMessageTempalteを用いています。
messagetemplates.org

// MessageTempalteを用いたログ出力
string p1 = "param1";
string p2 = "param2";

// Parameter values: param1, param2
logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);

各ログ API では、メッセージ テンプレートが使用されます。 メッセージ テンプレートには、指定される引数のためのプレースホルダーを含めることができます。 プレースホルダーには、数値ではなく名前を使用します。 プレースホルダーの名前ではなく、プレースホルダーの順序によって、値の指定に使用されるパラメーターが決まります。 次のコードでは、パラメーター名がメッセージ テンプレート内のシーケンスの外にあります。

C# でのログ記録 - .NET | Microsoft Learn

ただ最近MessageTempalteの仕様に全て対応しているわけではないのじゃないかということに気付いたのでそれを書き残して置きたいと思います。

概要

MessageTempalteの仕様としては本来プレースホルダーの中に数字を書き込むことで、順序を制御することができます。

Each property in the message template is associated with exactly one value in the argument list.

  • Templates that use numeric property names like {0} and {1} exclusively imply that arguments to the template are captured by numeric index
  • If any of the property names are non-numeric, then all arguments are captured by matching left-to-right with holes in the order in which they appear

// DeepL翻訳
メッセージ・テンプレートの各プロパティは、引数リストの中のちょうど1つの値と関連付けられ ている。

  • {0}や{1}のような数値プロパティ名を排他的に使用するテンプレートは、テンプレートへの引数が数値インデックスによって捕捉されることを意味します。
  • プロパティ名のいずれかが数値でない場合、すべての引数は、それらが現れる順序で穴と左から右へのマッチングによって捕捉される

例えばmessagetemplates-csharpというC#用MessageTemplateを実装したライブラリでは順序の制御をすることができます。
github.com

// arg1 : "2", arg2 : "1"
Console.WriteLine(MessageTemplate.Format("arg1 : {1}, arg2 : {0}", "1", "2"));

実験

プレースホルダーの中に数字を入れて実験してみます。

// Logger作成
using var factory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = factory.CreateLogger("Program");
        
// arg1 : 1, arg2 : 2
logger.LogInformation("arg1 : {1}, arg2 : {Test}", "1", "2");
        
// arg1 : 1, arg2 : 2
logger.LogInformation("arg1 : {1}, arg2 : {0}", "1", "2");

考察

公式ドキュメントを見てみてもプレースホルダーには数字を使用しないでと書かれているので、間接的に順序を制御できないよという意図が込められているのかも知れません。

各ログ API では、メッセージ テンプレートが使用されます。 メッセージ テンプレートには、指定される引数のためのプレースホルダーを含めることができます。 プレースホルダーには、数値ではなく名前を使用します。

.NET Core および ASP.NET Core でのログ記録 | Microsoft Learn


また実装を見るとLogValuesFormatterがコアになる箇所なのだと思うのですが、ぱっと見indexによる順序制御がなさそな気配があるのでやはり対応してないのかもしれません。
github.com