2012-11-26 6 views
5

Ich verwende Nlog um meine Ninjatrader Strategien zu loggen. Ich möchte in der Lage sein, die Strategie-ID allen meinen nLog-Nachrichten als Präfix hinzuzufügen, damit ich die Einträge für jedes Konto in der Strategie getrennt filtern kann.Variablen als Präfix zu allen nLog Nachrichten hinzufügen

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

Mein aktuelles Layout ist wie oben. Ich habe versucht, event-context: item zu verwenden, weiß aber nicht, wie ich das Kontextelement für alle Nachrichten drucken soll.

versuchte ich als

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

folge Aber es endete nur eine Zeile mit dem Kontext info auf der ersten Zeile Sim101 und nicht auf den anderen Linien zu drucken.

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 

Wie drucke ich den Sim101 auf allen Protokollzeilen?

Antwort

22

Die {event-context}LayoutRenderer schreibt einen Wert aus der LogEventInfo Objekt Properties Eigenschaft.

Eigenschaften ist ein Wörterbuch, in dem Sie benannte Werte speichern können, die NLog jeder Protokollnachricht hinzufügen soll.

Wenn Sie jede Protokollmeldung mit dem „StrategyId“ markieren wollen, die wirksam ist, wenn die Nachricht protokolliert wird, sollten Sie Ihre LogEventInfo so etwas wie diese Objekte erstellen:

LogEventInfo theEvent = new LogEventInfo(NLog.LogLevel.Debug, "", this.Account.Name); 
theEvent.Properties["StrategyId"] = "Sim101"; 
Logger.Log(theEvent); 

Ihr Layout würde wie folgt aussehen :

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

Wenn Sie Ihre Protokollierung Aufrufstellen weniger ausführlich sein wollen, Sie GlobalDiagnosticContext oder MappedDiagnosticContext nutzen könnten.

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

ein Layout wie folgt aus:

fileTarget.Layout = "${longdate} ${callsite} ${level} ${gdc:item=StrategyId} ${message}"; 

Wird jede Protokollmeldung verursachen mit dem aktuellen Wert von „StrategyId“ im globalen Wörterbuch markiert werden.

Zum Spaß können Sie auch eine fließende API-Erweiterungsmethode erstellen, die Ihre Eigenschaften auf die von Ihnen erstellten LogEventInfo-Objekte anwendet. So etwas wie diese (nicht getestet):

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

Und:

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

Wenn Sie mehr explizit sein wollen (und reduzieren mögliche

LogEventInfo WithProperty(this LogEventInfo theEvent, string name, string value) 
{ 
    theEvent.Properties[name] = value; 
    return theEvent; 
} 

Sie dann wie folgt verwenden könnte Tippfehler), könnten Sie spezifischere Erweiterungsmethoden wie diese machen:

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

EDIT: Die meisten Leute verwenden die Logger.Info, Logger.Debug, Logger.Trace, etc-Methoden, um ihre Protokollnachrichten zu schreiben, anstatt eine LogEventInfo erstellen und Log für jede Nachricht aufrufen.Es gibt vielleicht mehr Flexibilität, wenn Sie Ihre Objekte explizit erstellen, aber es macht auch Ihre Arbeit komplizierter.

Wenn Sie die Methoden Logger.Info, Logger.Debug, etc. verwenden und jede Protokollnachricht mit zusätzlichen Eigenschaften dekorieren möchten, können Sie das trotzdem tun.

Lasst uns sagen, dass Sie zwei Methoden haben (wie ich oben beschrieben) zwei verschiedene Strategien anwenden: ABC und DEF:

ein Layout wie folgt verwenden:

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

In jedem Fall protokolliert die Meldungen wird mit der "StrategyId" gekennzeichnet, die innerhalb der entsprechenden Funktion gesetzt ist.

Wenn Sie LogEventInfo-Objekte zum Erstellen Ihrer Nachrichten erstellen und verwenden möchten, müssen Sie wissen, dass die Eigenschaften einer LogEventInfo-Objektinstanz NUR für diese Instanz gelten. Wenn Sie eine LogEventInfo erstellen, ihre Eigenschaften festlegen, sie protokollieren und dann eine Nachricht mit Logger.Info, Logger.Debug usw. aufzeichnen, werden die Eigenschaften, die Sie für die ursprüngliche LogEventInfo festgelegt haben, NICHT angezeigt.

Zum Beispiel

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

ich die Logger.Info, Logger.Debug, Logger.Trace usw. Methoden empfehlen Ihre Nachrichten und entweder GlobalDiagnosticsContext oder MappedDiagnosticsContext geben Sie die zusätzlichen Informationen, die Sie in jeder aufgenommen werden möchten, melden Sie sich Protokollnachricht

Im Allgemeinen denke ich, dass ich auch, dass Sie die Logger.Info, Logger.Debug, Logger.Trace Methoden ENTWEDER ODER LogEventInfo + Logger.Log, aber nicht beide empfehlen würde. Die Verwendung von beiden, insbesondere wenn Sie versuchen, zusätzliche Kontextwerte (StrategyId) hinzuzufügen, kann verwirrend werden.

Ich kann eine Analogie zur Installation von Software machen. Wenn Sie Software auf Ihrem Computer installieren, haben Sie normalerweise die Wahl zwischen der Installation "Typisch", bei der das Installationsprogramm die zu installierenden Komponenten installiert, oder "Benutzerdefiniert", bei der Sie die Komponenten auswählen und auswählen, die Sie installieren möchten. Ich weiß nicht von dir, aber ich wähle normalerweise die "typische" Installation. Mit Logger.Info, Logger.Debug, Logger.Trace ist wie die "Typische" Installation. Dies sind die am häufigsten verwendeten Methoden für die Protokollierung. Die Verwendung von LogEventInfo + Logger.Log ist mehr wie die Wahl von "Custom" Installation. Die Implikation, wenn Sie LogEventInfo verwenden, ist, dass die "typischen" Logging-Methoden nicht Ihren Bedürfnissen entsprechen.

Während Sie mit NLog arbeiten, werden Sie mit der Funktionsweise vertrauter und einige dieser Probleme werden für Sie deutlicher.

Beachten Sie, dass GlobalDiagnosticsContext wirklich global ist. Es ist ein statisches Objekt. Wenn Sie also Multithreading durchführen, besteht die Gefahr eines Konflikts, wenn zwei Threads versuchen, dem Wörterbuch einen Wert mit demselben Namen hinzuzufügen.

MappedDiagnosticsContext ist Thread lokal (es verwendet ein static static-Thread-Wörterbuch, um seine Werte zu speichern), also ist es wahrscheinlich besser, in einer Multithreading-Situation zu verwenden.

Wenn Sie Lust zu bekommen und Umfang automatisch die Werte, die Sie im GlobalDiagnosticsContext setzen (oder der MappedDiagnosticsContext), könnten Sie eine Klasse wie folgt erstellen:

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

Und man könnte es wie folgt verwenden:

private void ApplyStrategyDEF() 
    { 
    using (new ScopedGlobalContext("StrategyId", "DEF")) 
    { 
     //Do some stuff 

     logger.Debug("Hello from DEF"); 

     var x = CalculateSomeValue(); 

     logger.Debug("Value = {0}", x); 
    } 
    } 

Dies wird das StrategyId, DEF Namen Wertepaar im GlobalDiagnosticsContext Wörterbuch setzen, wenn der using Umfang beginnt, und es wird entfernen, wenn die using Umfang beendet.

+0

hier ist meine volle Frage: Muss ich ein Ereignis vor dem Aufruf einer Trace-Funktion jedes Mal hinzufügen? Wenn ich die Ereigniseigenschaften hinzufüge und logger.info (theEvent), mache, druckt es sofort das Suffix für mein Protokoll. für zB 2012-11-28 14: 18: 52.3277 NinjaTrader.Strategy.LODHOD.OnStartUp Info Log-Ereignis: Logger = '' Level = Info Nachricht = 'd4d0d3849c2440f5b41de65d744ede61' SequenzID = 270 Die nächste logger.info konnte jedoch nicht erfassen Meine Eigenschaften 2012-11-28 14: 18: 52.9996 NinjaTrader.Strategy.LODHOD.OnBarUpdate Info BAR UPDATE Der Code, den ich verwendet habe, ist hier. http://codeviewer.org/view/code:2c95 – junkone

+0

und log ich benutze ist hier. http://codeviewer.org/view/code:2c96 – junkone

+0

Sie müssen nicht die LogEventInfo-Klasse verwenden, um Ihre Nachrichten zu erstellen, und die Log-Methode, um sie zu protokollieren. Normalerweise tun die meisten Leute nicht. Sie verwenden die Methoden .Info, .Debug, .Trace usw., um ihren Protokollierungscode zu schreiben. Ich werde meiner Antwort einige Beispiele hinzufügen. – wageoghe