2012-11-26 14 views
5

私はNinjatraderの戦略を記録するためにNlogを使用しています。戦略の各アカウントに関連するエントリを個別にフィルタリングできるように、すべてのnLogメッセージにプレフィックスとして戦略IDを追加できます。すべてのnLogメッセージにプレフィックスとして変数を追加します。

fileTarget.Layout = "${longdate} ${callsite} ${level} ${event-context:item=MyValue} ${message}";` 

現在のレイアウトは上記のとおりです。私は、イベントコンテキスト:アイテムを使用しようとしましたが、すべてのメッセージのコンテキストアイテムを印刷する方法を知らない。

Logger log = LogManager.GetCurrentClassLogger(); 
LogEventInfo theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name); 
logger.Log(theEvent); 

を次のように私がしようとしたが、それは他の行の1行目Sim101とないのコンテキスト情報を持つ唯一の1行を印刷し終わりました。

2012-11-26 15:09:47.9777 NinjaTrader.Strategy.LODHOD.OnStartUp Debug Sim101 
2012-11-26 15:09:48.3996 NinjaTrader.Strategy.LODHOD.OnBarUpdate Trace BAR UPDATE 
2012-11-26 15:09:49.7902 NinjaTrader.Strategy.LODHOD.EntryOrders Info PLACED ENTRY ORDERS 

どのようにすべてのログ行にSim101を印刷しますか?

答えて

22

{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").WithProperty("SomethingElse", someLocalVariable); 

var theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name).WithProperty("StrategyId", "ABC"); 

そして、これタイプミス)、次のようなより具体的な拡張メソッドを作成できます。

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

編集: ほとんどの人はLogEventInfoを作成し、各メッセージにログを呼び出すのではなく、Logger.Info,Logger.DebugLogger.Traceなどの方法を使用してログメッセージを書きます。LogEventInfoオブジェクトを明示的に作成すると、より柔軟な利用が可能になりますが、作業が複雑になります。

Logger.InfoLogger.Debugなどのメソッドを使用して、追加のプロパティで各ログメッセージを修飾したい場合でも、それを行うことができます。

二つの異なる戦略を適用するのは、(私は上記のように)あなたは2つの方法があるとしましょう:ABCとDEFを:メッセージがログに記録され、それぞれの場合には

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.InfoLogger.DebugLogger.Trace、などの方法を使用して使用していずれかGlobalDiagnosticsContextまたはMappedDiagnosticsContext推薦ログメッセージ。

は一般的に、私はまた、両方ではなく、Logger.Trace方法OR LogEventInfo + Logger.LogLogger.Debug、あなたがLogger.Infoのいずれかを使用することをお勧めだろうと思います。両方を使用すると、特にコンテキスト値(StrategyId)を追加しようとすると混乱する可能性があります。

私はソフトウェアのインストールに似ています。通常、コンピュータにソフトウェアをインストールするときは、インストールするコンポーネントをインストーラにインストールさせる「標準」インストールを選択するか、インストールするコンポーネントを選択して選択する「カスタム」を選択します。私はあなたについて知りませんが、私は通常、 "典型的な"インストールを選択します。 Logger.InfoLogger.DebugLogger.Traceは「標準」インストールと同じです。これらは、ログのために最も一般的に使用される方法です。 LogEventInfo + Logger.Logを使用することは、「カスタム」インストールを選択するようなものです。 LogEventInfoを使用している場合は、「標準的な」ロギング方法がニーズを満たさないということです。

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

これはusingスコープが始まるときGlobalDiagnosticsContext辞書にStrategyId、DEF名前と値のペアを置くとするときusingスコープが終了、それを削除します。

+0

ここに私の完全な質問です: 毎回トレース機能を呼び出す前にイベントを追加する必要がありますか?私はイベントのプロパティを追加し、logger.info(theEvent)を実行し、 はすぐに私のログのサフィックスを表示しました。 例:2012-11-28 14:18:52.3277 NinjaTrader.Strategy.LODHOD.OnStartUp情報ログイベント:Logger = '' Level = Info Message = 'd4d0d3849c2440f5b41de65d744ede61' SequenceID = 270 次のlogger.infoはキャプチャしませんでした私の物件 2012-11-28 14:18:52.9996 NinjaTrader.Strategy.LODHOD.OnBarUpdate情報バー更新 私が使用したコードはここにあります。 http://codeviewer.org/view/code:2c95 – junkone

+0

と私が使ったログはここにあります。 http://codeviewer.org/view/code:2c96 – junkone

+0

LogEventInfoクラスを使用してメッセージを作成する必要はなく、ログを記録するためにLogメソッドを使用する必要はありません。通常、ほとんどの人はそうしません。彼らは、.Info、.Debug、.Trace、etcメソッドを使用してロギングコードを記述します。私は私の答えにいくつかの例を追加します。 – wageoghe

関連する問題