2008-12-02 11 views
52

Ich habe mit log4net die Möglichkeit gesehen, einen Pro-Thread-Stapel von Kontext-Labels namens NDC zu verwenden.Wann 'verschachtelter Diagnosekontext' (NDC) zu verwenden ist?

Die auf diesem Stapel gedrückten Etiketten werden in einem PatternLayout angezeigt, indem Sie den Formatparameter %x oder %ndc angeben.

Die Benutzung ist so etwas wie:

ILog log = log4net.LogManager.GetLogger(...) ; 

//pattern layout format: "[%ndc] - %message%newline" 

log.Info("message 1"); 
using(log4net.NDC.Push("context") 
{ 
    using(log4net.NDC.Push("inner_context") 
    { 
     log.Info("message 2"); 
    } 
    log.Info("message 3"); 
} 
log.Info("message 4"); 

Der Ausgang ist so etwas wie:

null - message 1 
context inner_context - message 2 
context - message 3 
null - message 4 

In Ihrem Programmiererfahrung mit log4net, wenn Sie diese Funktion nützlich sein aufmerksam geworden?

+3

Es ist wie log4net aussieht hat NDC veraltet für allgemeine Zwecke Kontext stapelt. Der Ratschlag in den Antworten ist immer noch wahr, aber http://logging.apache.org/log4net/release/manual/contexts.html sagt "Der NDC (Nested Diagnostic Context) existiert aus Gründen der Kompatibilität mit älteren Versionen von log4net.Diese Hilfsklasse implementiert einen Stapel, der in der Threadkontexteigenschaft namens NDC gespeichert wird. " –

Antwort

24

In einer Serveranwendung wie ASP.NET.

Zum Beispiel können Sie Informationen über die aktuelle Anfrage an den NDC senden.

+3

Ein Link zu einem Beispiel wäre nützlich –

+5

Ich habe keinen Link, aber denke an die Situation, in der du eine ASP.NET-Anwendung mit vielen hast Wenn Sie die Anforderungs-ID (entweder generiert oder mit einem Bezeichner aus der Anfrage) in den NDC übertragen, können Sie alle Protokollnachrichten für eine bestimmte Anforderung über alle Ebenen Ihrer Anwendung hinweg korrelieren Low-Level-Komponenten, die nichts über ASP.NET wissen, können mit der ursprünglichen Anforderung korreliert werden. –

+0

@Johnny_D, Beispiel? [Link zum Beispiel unten] (http://Stackoverflow.com/a/17344012/939250) –

18

Diese Funktion ist nützlich, wenn Sie viele Protokolle durchlaufen müssen. Wann würden Sie viele Protokolle haben? Fehlerhaften Fehler in einem Produktionssystem mit Interleaving-Ausgaben diagnostizieren. Wenn Sie mehr Kontexte haben, können Sie die Ausgabe filtern oder nicht benötigte Protokolle ausgeben.

Ein weiterer Fall verschachtelten Kontexten könnte nützlich sein, wenn eine Methode oder ein Feature mehrmals in verschiedenen Kontexten aufgerufen wird und Sie eine Möglichkeit benötigen, zwischen ihnen zu unterscheiden.

71

Wollen Sie ein Beispiel?

Nehmen Sie die folgende Web-API geschrieben ASP.NET MVC4 mit:

// GET api/HypervResource 
public string Get() 
{ 
    logger.Debug("Start of service test"); 
    System.Threading.Thread.Sleep(5000); // simulate work 
    logger.Debug("End of service test"); 
    return "HypervResource controller running, use POST to send JSON encoded RPCs"; 
} 

Wenn Server gleichzeitige HTTP-Requests vorgenommen werden, kann die Protokollierung verschachtelt bekommen. Z.B.

2013-06-27 13:28:11,967 [10] DEBUG HypervResource.WmiCalls [(null)] - Start of service test 
2013-06-27 13:28:12,976 [12] DEBUG HypervResource.WmiCalls [(null)] - Start of service test 
2013-06-27 13:28:14,116 [13] DEBUG HypervResource.WmiCalls [(null)] - Start of service test 
2013-06-27 13:28:16,971 [10] DEBUG HypervResource.WmiCalls [(null)] - End of service test 
2013-06-27 13:28:17,979 [12] DEBUG HypervResource.WmiCalls [(null)] - End of service test 
2013-06-27 13:28:19,119 [13] DEBUG HypervResource.WmiCalls [(null)] - End of service test 

In diesem einfachen Beispiel, könnten Sie die Thread-ID verwenden Anfragen zu unterscheiden, aber das kann schwierig werden, wie die Protokolldatei in Komplexität wächst.

Eine bessere Alternative besteht darin, eindeutige Bezeichner bereitzustellen, die Protokollnachrichten für die gleiche Anforderung gruppieren. Wir können den Code in Bezug auf die folgende Update:

// GET api/HypervResource 
public string Get() 
{ 
    using(log4net.NDC.Push(Guid.NewGuid().ToString())) 
    { 
     logger.Debug("Start of service test"); 
     System.Threading.Thread.Sleep(5000); // simulate work 
     logger.Debug("End of service test"); 
     return "HypervResource controller running, use POST to send JSON encoded RPCs"; 
    } 
} 

Dies erzeugt ein Protokoll, das Sie grep können die Probleme mit einer bestimmten Anforderung zugeordnet ist, um zu sehen. Z.B.

2013-06-27 14:04:31,431 [11] DEBUG HypervResource.WmiCalls [525943cb-226a-43c2-8bd5-03c258d58a79] - Start of service test 
2013-06-27 14:04:32,322 [12] DEBUG HypervResource.WmiCalls [5a8941ee-6e26-4c1d-a1dc-b4d9b776630d] - Start of service test 
2013-06-27 14:04:34,450 [13] DEBUG HypervResource.WmiCalls [ff2246f1-04bc-4451-9e40-6aa1efb94073] - Start of service test 
2013-06-27 14:04:36,434 [11] DEBUG HypervResource.WmiCalls [525943cb-226a-43c2-8bd5-03c258d58a79] - End of service test 
2013-06-27 14:04:37,325 [12] DEBUG HypervResource.WmiCalls [5a8941ee-6e26-4c1d-a1dc-b4d9b776630d] - End of service test 
2013-06-27 14:04:39,453 [13] DEBUG HypervResource.WmiCalls [ff2246f1-04bc-4451-9e40-6aa1efb94073] - End of service test 
0

NDC.Push wurde veraltet. Der bevorzugte Weg, jetzt (ThreadContext.Stacks["NDC"]) ist dies:

var disposable = ThreadContext.Stacks["NDC"].Push("context"); 
try 
{ 
    Log.Info("begin"); // optional, but nice 
    ... 
} 
finally 
{ 
    Log.Info("end"); // optional, but nice 
    disposable.Dispose(); 
} 

Denken Sie daran, Ihre Conversion-Muster zu überprüfen, so dass es %property{NDC} beinhaltet:

<layout type="log4net.Layout.PatternLayout"> 
    <conversionPattern 
    value="%date [%2thread] %-5level [%property{NDC}] - %.10240message%newline" /> 
</layout>