2010-04-12 6 views
5

Ich bin in C# -Protokollierung und ich möchte nicht meine Log-Nachrichten verbringen jede Zeit Verarbeitung, wenn die Nachricht unterhalb der Logging-Schwelle ist. Das Beste, was ich log4net sehen kann, ist eine Schwellwertüberprüfung NACH Auswertung der Log-Parameter.Leistungstricks für C# Logging

Beispiel:

_logger.Debug("My complicated log message " + thisFunctionTakesALongTime() + " will take a long time") 

Auch wenn der Schwellenwert über Debug ist, wird thisFunctionTakesALongTime noch ausgewertet werden.

In log4net Sie sollen _logger.isDebugEnabled verwenden, so dass Sie mit

if(_logger.isDebugEnabled) 
    _logger.Debug("Much faster") 

am Ende möchte ich wissen, ob eine bessere Lösung für .net Protokollierung gibt es nicht einen Scheck jedes Mal, wenn ich will mit sich bringt aufzeichnen.

In C++ Ich bin

LOG_DEBUG("My complicated log message " + thisFunctionTakesALongTime() + " will take no time") 

da mein LOG_DEBUG Makro wird die Protokollebene überprüft selbst zu tun erlaubt. Das gibt mir die Möglichkeit, eine 1-Zeilen-Log-Nachricht in meiner App zu haben, die ich sehr bevorzuge. Kennt jemand eine Möglichkeit, dieses Verhalten in C# zu replizieren?

Antwort

8

Wenn Sie .NET 3.5 (C# 3.0) anvisieren können, können Sie extension methods verwenden, um die if-Anweisungen zu umbrechen.

so können Sie das Äquivalent "Makro" tun:

logger.Log_Debug("Much faster"); 

logger.Log_Debug(() => { "My complicated log message " + thisFunctionTakesALongTime() + " will take no time" }); 

indem Sie auf die in dieser Methode Verpackung:

public class Log4NetExtensionMethods { 
    // simple string wrapper 
    public void Log_Debug(this log4net.ILog logger, string logMessage) { 
     if(logger.isDebugEnabled) { 
      logger.Debug(logMessage); 
     } 
    } 

    // this takes a delegate so you can delay execution 
    // of a function call until you've determined it's necessary 
    public void Log_Debug(this log4net.ILog logger, Func<string> logMessageDelegate) { 
     if(logger.isDebugEnabled) { 
      logger.Debug(logMessageDelegate()); 
     } 
    } 
} 
+0

Aber wenn ich Funktionen evaluiere, um die Protokollnachricht zu erhalten, würde das nicht genauso langsam sein? Ich möchte alle Funktionsauswertungen vermeiden, wenn der Loglevel unterhalb meiner Schwelle liegt. – Charles

+1

Sie haben Recht, dass Sie die Funktionsbewertung verzögern müssen.Sehen Sie sich mein Update an, das einen anonymen Delegaten verwendet. –

+1

D'oh, das war meine Antwort auch. Ich sollte Sie warnen: Wenn Sie nach Geschwindigkeit suchen, möchten Sie keine Delegierten verwenden. Sie sollten einfach den Treffer nehmen und wenn if (logger.isDebugEnabled) um etwas teures verwenden. Es gibt keine Lösung, die sowohl performant als auch elegant ist. – bobbymcr

-2

Ohne Präprozessor Sie SOL sind. Natürlich gibt es nichts, was Sie daran hindert, eins zu verwenden, bevor Sie Ihren Code dem C# -Compiler zuführen.

+0

anonyme Delegierte und zusätzliche Klassen - wow, das ist eine Menge tippen. – blammo

1

Das Problem hier ist, dass alle Methodenparameter ausgewertet werden müssen, bevor die Methode aufgerufen wird. In Anbetracht der von Ihnen verwendeten Syntax gibt es keinen Weg dazu. Da C# keinen echten Präprozessor oder Makros hat, können Sie nichts wie "LOG_DEBUG" tun. Das Beste, was Sie tun können, ist if (logger.isDebugEnable) wie vorgeschlagen zu verwenden.

Das einzige, was mir einfällt, ist vielleicht etwas wie einen Lambda-Ausdruck zu verwenden, um die Auswertung zu verzögern. Aber ich würde Sie warnen, dass dies wird sicherlich mehr Leistung am Ende haben.

internal class Sample 
{ 
    private static void Main(string[] args) 
    { 
     DelayedEvaluationLogger.Debug(logger,() => "This is " + Expensive() + " to log."); 
    } 

    private static string Expensive() 
    { 
     // ... 
    } 
} 

internal static class DelayedEvaluationLogger 
{ 
    public static void Debug(ILog logger, Func<string> logString) 
    { 
     if (logger.isDebugEnabled) 
     { 
      logger.Debug(logString()); 
     } 
    } 
} 
+0

Sind Lambda-Ausdrücke so teuer? – Charles

+2

@Charles: lambdas sind relativ billig, soweit späte Bindung geht, aber viel teurer als eine boolesche Prüfung und ein Methodenaufruf. In meinem einfachen Test über eine Milliarde Iterationen (Code hier: http://pastebin.com/aRtMtsxz), habe ich etwa 25% Overhead für Lambda vs Boolean Check gemessen, wenn die Protokollierung nicht aktiviert war. Mit einem zwischengespeicherten Lambda (speichern Sie das Lambda auf einem Feld, so dass es nicht jedes Mal neu erzeugt wird), gibt es etwas weniger Overhead (ein Wurf unter 20%). – bobbymcr

2

17.4.2 Das Conditional-Attribut

Das Attribut Conditional ermöglicht die Definition der bedingten Methoden. Das Conditional-Attribut zeigt eine Bedingung durch Testen eines bedingten Kompilierungssymbols an. Aufrufe an eine bedingte Methode werden entweder eingeschlossen oder weggelassen, abhängig davon, ob dieses Symbol zum Zeitpunkt des Aufrufs definiert ist. Wenn das Symbol definiert ist, wird der Anruf einbezogen. Andernfalls wird der Anruf (einschließlich der Auswertung der Parameter des Anrufs) weggelassen.

[ Conditional("DEBUG") ] 
public static void LogLine(string msg,string detail) 
{ 
    Console.WriteLine("Log: {0} = {1}",msg,detail); 
} 

public static void Main(string[] args) 
{ 
    int Total = 0; 
    for(int Lp = 1; Lp < 10; Lp++) 
    { 
     LogLine("Total",Total.ToString()); 
     Total = Total + Lp; 
    } 
} 
+0

Das ist interessant, ich werde mehr darüber recherchieren. MSDN: http://msdn.microsoft.com/en-us/library/aa664622%28VS.71%29.aspx – Charles

+1

Ich würde annehmen, dass die besseren Protokollierungsbibliotheken diese Technik bereits verwenden. – blammo

+1

Nur weil Sie eine "logger.debug" -Methode aufrufen, bedeutet das nicht, dass Sie tatsächlich im Debug-Modus laufen. Der Name "debug" ist eigentlich nur der Methodenname für einen beliebigen Schwellenwert, wie er vom Anwendungsentwickler definiert wurde. Ich wäre überrascht, wenn Log4Net, EnterpriseLibrary, etc ... tatsächlich bedingte Attribute verwenden würden, da das Attribut auf dem Vorhandensein eines Kompilierungssymbols beruht. –