は、オブジェクトのプロパティ{event-context}
LayoutRenderer
から値を書き込みます。LogEventInfo
Properties
プロパティは、NLogが各ログメッセージに追加する名前付きの値を格納できる辞書です。
メッセージがログに記録されるときに有効な「StrategyId」で各ログメッセージにタグを付ける場合は、次のようなLogEventInfoオブジェクトを作成する必要があります。
LogEventInfo theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name);
theEvent.Properties["StrategyId"] = "Sim101";
Logger.Log(theEvent);
レイアウトは次のようになります。
fileTarget.Layout = "${longdate} ${callsite} ${level} ${event-context:item=StrategyId} ${message}";
ロギング呼び出しサイトの冗長性を低くしたい場合は、GlobalDiagnosticContextまたはMappedDiagnosticContextを使用できます。
private void ApplyStrategyABC()
{
NLog.GlobalDiagnosticContext.Set("StrategyId","ABC");
//Do some stuff
LogEventInfo theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name);
Logger.Log(theEvent);
NLog.GlobalDiagnosticContext.Remove("StrategyId");
}
private void ApplyStrategyDEF()
{
NLog.GlobalDiagnosticContext.Set("StrategyId","DEF");
//Do some stuff
LogEventInfo theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name);
Logger.Log(theEvent);
NLog.GlobalDiagnosticContext.Remove("StrategyId");
}
次のようなレイアウトを使用します。
fileTarget.Layout = "${longdate} ${callsite} ${level} ${gdc:item=StrategyId} ${message}";
各ログメッセージは、グローバルディクショナリの「StrategyId」の現在の値でタグ付けされます。
楽しみのために、作成したLogEventInfoオブジェクトにプロパティを適用するような流暢なAPI拡張メソッドを作成することもできます。このようなもの(テストされていない):
LogEventInfo WithProperty(this LogEventInfo theEvent, string name, string value)
{
theEvent.Properties[name] = value;
return theEvent;
}
次に、次のように使用できます。
var theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name).WithProperty("StrategyId", "ABC");
この:
var theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name).WithProperty("StrategyId", "ABC").WithProperty("SomethingElse", someLocalVariable);
より明確にしたい(そして起こりうるタイプミスを減らしたい)場合は、次のようなより具体的な拡張メソッドを作成することができます。
LogEventInfo WithStrategy(this LogEventInfo theEvent, string strategy)
{
theEvent.Properties["StrategyId"] = strategy;
return theEvent;
}
LogEventInfo WithCurrency(this LogEventInfo theEvent, string currency)
{
theEvent.Properties["Currency"] = currency;
return theEvent;
}
var theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name).WithStrategy("ABC").WithCurrency("US dollars");
編集:ほとんどの人は、Logger.Info
メッセージごとにログを作成して呼び出すのではなく、、、、などのメソッドを使用してログメッセージを書き込みLogger.Debug
ます。オブジェクトを明示的に作成すると、おそらくより柔軟性がありますが、作業がより複雑になります。Logger.Trace
LogEventInfo
LogEventInfo
、、などのメソッドを使用しLogger.Info
、Logger.Debug
各ログメッセージを追加のプロパティで装飾する場合でも、それを行うことができます。
ABCとDEFの2つの異なる戦略を適用するための2つの方法(上記のように)があるとしましょう。
次のようなレイアウトを使用します。
fileTarget.Layout = "${longdate} ${callsite} ${level} ${gdc:item=StrategyId} ${message}";
public class MyClass
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private void ApplyStrategyABC()
{
NLog.GlobalDiagnosticContext.Set("StrategyId","ABC");
//Do some stuff
logger.Debug("Hello from ABC!");
var x = CalculateSomeValue();
logger.Debug("Value = {0}", x);
NLog.GlobalDiagnosticContext.Remove("StrategyId");
}
private void ApplyStrategyDEF()
{
NLog.GlobalDiagnosticContext.Set("StrategyId","DEF");
//Do some stuff
logger.Debug("Hello from DEF");
var x = CalculateSomeValue();
logger.Debug("Value = {0}", x);
NLog.GlobalDiagnosticContext.Remove("StrategyId");
}
}
In you program call your two strategies:
var myClass = new MyClass();
myClass.ApplyStrategyABC();
myClass.ApplyStrategyDEF();
いずれの場合も、ログに記録されるメッセージは、対応する関数内に設定されている「StrategyId」でタグ付けされます。
LogEventInfoオブジェクトを作成して使用してメッセージを作成する場合は、1つのLogEventInfoオブジェクトインスタンスのプロパティがそのインスタンスにのみ適用されることを理解する必要があります。LogEventInfoを作成し、そのプロパティを設定してログに記録し、Logger.Info、Logger.Debugなどを使用してメッセージをログに記録すると、元のLogEventInfoに設定したプロパティは表示されません。
例えば、
var logger = LogManager.GetCurrentClassLogger();
var theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", "Hello 1");
theEvent.Properties["StrategyId"] = "ABC";
//This message will be tagged with StrategyId = ABC if the layout uses the event-context LayoutRenderer
logger.Log(theEvent);
//This message will NOT be tagged with StrategyId = ABC because that value was only added to the LogEventInfo
//object that was created above. Another way to think about this is that internally
//NLog creates a LogEventInfo for each message that is logged via the Debug, Trace, etc
//methods.
logger.Debug("Hello 2");
、、、などのメソッドを使用してメッセージをログに記録し、またはのいずれかを使用しLogger.Info
て、各ログメッセージに含める追加情報を指定することをお勧めします。Logger.Debug
Logger.Trace
GlobalDiagnosticsContext
MappedDiagnosticsContext
一般的には、、、メソッド、または+のいずれかを使用することをお勧めしますが、両方Logger.Info
を使用することはお勧めしません。特にコンテキスト値(StrategyId)を追加しようとしている場合は、両方を使用すると混乱する可能性があります。Logger.Debug
Logger.Trace
LogEventInfo
Logger.Log
ソフトウェアのインストールに例えることができます。通常、コンピューターにソフトウェアをインストールするときは、インストーラーにインストールするコンポーネントをインストールさせる「標準」インストールを選択するか、インストールするコンポーネントを選択して選択する「カスタム」インストールを選択できます。あなたのことはわかりませんが、私は通常「標準」インストールを選択します。Logger.Info
、、を使用することはLogger.Debug
、Logger.Trace
「一般的な」インストールのようなものです。これらは、ロギングに最も一般的に使用される方法です。LogEventInfo
+を使用Logger.Log
することは、「カスタム」インストールを選択することに似ています。使用している場合の意味LogEventInfo
は、「一般的な」ロギング方法ではニーズが満たされないということです。
NLogを使用するにつれて、NLogがどのように機能するかを理解し、これらの問題のいくつかがより明白になります。
GlobalDiagnosticsContext
それは本当にグローバルであることに注意してください。静的オブジェクトです。したがって、マルチスレッドを使用している場合、2つのスレッドが同じ名前の値をディクショナリに追加しようとすると、競合が発生する可能性があります。
MappedDiagnosticsContext
はスレッドローカルであるため(値を格納するためにスレッド静的ディクショナリを使用します)、マルチスレッドの状況で使用する方がおそらく良いでしょう。
GlobalDiagnosticsContext(またはMappedDiagnosticsContext)に設定した値を空想して自動的にスコープしたい場合は、次のようなクラスを作成できます。
public class ScopedGlobalContext : IDisposable
{
private string n;
private string v;
public ScopedGlobalContext(string name, string value)
{
n = name;
v = value;
NLog.GlobalDiagnosticsContext.Set(n, v);
}
public void Dispose()
{
NLog.GlobalDiagnosticsContext.Remove(n);
}
}
そして、あなたはそれをこのように使うことができます:
private void ApplyStrategyDEF()
{
using (new ScopedGlobalContext("StrategyId", "DEF"))
{
//Do some stuff
logger.Debug("Hello from DEF");
var x = CalculateSomeValue();
logger.Debug("Value = {0}", x);
}
}
これにより、スコープの開始時にStrategyIdとDEFの名前と値のペアがGlobalDiagnosticsContext
ディクショナリに配置され、スコープの終了using
時に削除されます。using