Makro-Frage bzgl. Logging



  • Aaaalso, ich versuch's möglichst einfach zu halten.

    Ich hab ein Logging-Makro "Debug", das wird z.B. so benutzt

    Debug((LP_Debug, "Eine tolle Loggingausgabe"));
    

    Es wird zweimal geklammert, da Makros ja nur ein Ausdruck übergeben werden kann. An die entsprechende Stelle kopiert der Compiler dann folgendes:

    #ifndef NDEBUG
        	#define Debug(x)								                 \
        	{													             \
        		CMessage *pMsg = new CMessage(__FILE__, __LINE__); \
        		pMsg->SetMsg x ;                                             \
        		CMessageHandler::Instance()->Log(pMsg);                 \
        		delete pMsg;                                                 \
        	}
        #else
        	#define Debug(x) {}
        #endif
    

    D.h. es wird ein Objekt vom Typ CMessage angelegt und die Methode SetMsg wie folgt aufgerufen:

    pMsg->SetMsg x ;  
    =
    pMsg->SetMsg(LP_Debug, "Eine tolle Loggingausgabe");
    

    Soweit, so gut. Jetzt kann man die Loggingausgaben komplett zur Compilezeit entfernen, wenn das define

    #define NDEBUG
    

    gesetzt wird, da in in diesem Fall von dem Compiler nur zwei geschweifte Klammern an die Stelle kopiert werden: {}.

    Jetzt die neue Anforderung
    Es soll möglich sein alle Loggingtypen (LP_Debug,LP_Warning,LP_Critical,...) separat zur Compilezeit entfernen zu können.
    Bei dem Code so wie es jetzt ist muss ja immer erst die Message angelegt werden, damit ich später über eine Methode den Typen herausbekommen kann. Das wäre ja schon nach der Compilierung.

    Seh ich das richtig, dass meine einzige Lösungsmöglichkeit darin besteht, mehrere Makros einzuführen, die man dann separat ausschalten kann?

    Aus

    Debug((LP_Debug, "Eine tolle Loggingausgabe"));
    

    würde dann

    LP_Debug(("Eine tolle Loggingausgabe"));
    

    werden. Entsprechend für alle anderen Typen z.B.

    LP_Warning(("Eine tolle Warning-Ausgabe"));
    

    Oder habt ihr da eine andere Idee? Bzw. geht das in meinem Fall überhaupt anders 😕



  • Aus dem einen Doppelparameter einzelne machen und dann abfragen mit zB:

    #define DEBUG(TYP, TEXT)...
    
    if (TYP == LP_DEBUG) usw.
    

  • Administrator

    Logger5000 schrieb:

    Es wird zweimal geklammert, da Makros ja nur ein Ausdruck übergeben werden kann.

    Aja? Das wäre mir neu ...

    Ich würde das so machen:

    #ifdef _DEBUG
    
      void debug_log(ErsterTyp erstesArgument, ZweiterTyp zweitesArgument)
      {
        CMessage Message(__FILE__, __LINE__);
        Message.SetMsg(erstesArgument, zweitesArgument);
        CMessageHandler::Instance()->Log(&Message);
      }
    
      #define DEBUG_LOG(x, y) debug_log(x, y)
    
    #else
      #define DEBUG_LOG(x, y)
    #endif
    
    // Verwendung:
    DEBUG_LOG(LP_Debug, "Hallo!");
    

    Dein zweites Problem oder eigentliches Problem verstehe ich allerdings nicht. Vor allem was diesen Satz betrifft:

    Bei dem Code so wie es jetzt ist muss ja immer erst die Message angelegt werden, damit ich später über eine Methode den Typen herausbekommen kann. Das wäre ja schon nach der Compilierung.

    Willst du vielleicht das folgende?

    #ifdef _DEBUG
      // wie oben, nur zusätzlich:
      #define DEBUG_WARNING(x) debug_log(LP_Warning, x)
    #else
      #define DEBUG_LOG(x, y)
      #define DEBUG_WARNING(x)
    #endif
    

    Grüssli



  • oder templates nehmen. erhöht aber die compile time, dafür kann man solche logging sachen feiner lösen...



  • Dravere schrieb:

    Dein zweites Problem oder eigentliches Problem verstehe ich allerdings nicht. Vor allem was diesen Satz betrifft:

    Bei dem Code so wie es jetzt ist muss ja immer erst die Message angelegt werden, damit ich später über eine Methode den Typen herausbekommen kann. Das wäre ja schon nach der Compilierung.

    Willst du vielleicht das folgende?

    #ifdef _DEBUG
      // wie oben, nur zusätzlich:
      #define DEBUG_WARNING(x) debug_log(LP_Warning, x)
    #else
      #define DEBUG_LOG(x, y)
      #define DEBUG_WARNING(x)
    #endif
    

    Grüssli

    Ja es geht in die richtige Richtung. Meine Frage bezieht sich auf das Überprüfung um welchen Typ der Nachricht es sich handelt.
    Bei deiner Lösung

    #define DEBUG_LOG(x, y)
      #define DEBUG_WARNING(x)
    

    würde die Fallunterscheidung ja wegfallen, weil der Benutzer explizit auswählt, was er haben will.

    Tut er das nicht, so komm ich doch nicht darum herum, diese Fallunterscheidung mit "richtigen" if-Bedingungen zu machen.

    Oder geht mit Makros irgendwie sowas:

    #ifndef (NO_WARNINGS && TYPE == LP_WARNING) /* Warningnachricht erstellen */
    

    So das der Typ wirklich schon vom Compiler geprüft wird?
    😕



  • Nur mal so aus interesse:
    Kommt bei Draveres Vorschlag mit der Funktion für die Zeile CMessage Message(__FILE__, __LINE__); nicht immer die Zeilennummer in der debug_log FUnktion selbst raus? Eigentlich will man doch die Zeile haben, an der die Funktion aufgerufen wird, oder?



  • Tachyon schrieb:

    Nur mal so aus interesse:
    Kommt bei Draveres Vorschlag mit der Funktion für die Zeile CMessage Message(__FILE__, __LINE__); nicht immer die Zeilennummer in der debug_log FUnktion selbst raus? Eigentlich will man doch die Zeile haben, an der die Funktion aufgerufen wird, oder?

    Jupp.



  • Okay, anders formuliert:

    Kann ich den Typen der Nachricht vom Compiler überprüfen lassen mit irgendwie

    #if TYPE==BLA

    oder mussich das tatsächlich zur Laufzeit machen mit

    if(TYPE===BLA)



  • Ich würde nicht allzuviel Zeit darauf verschwenden eine "if-freie" Lösung zu suchen, bevor du die "mit-if" Lösung nicht ausprobiert hast.
    Eigentlich sollte der Compiler ein "if(konstante == konstante)" im Release-Build komplett eliminieren. Diese Optimierung ist so einfach dass das wohl sogar 10 Jahre alte Compiler wie VC6 hinbekommen sollten.

    Auch durch Templates entsteht oft solcher Code, und um gute Performance mit den heute üblichen Template-Schlachten hinzubekommen müssen heutige Compiler solche Dinge auch gut optimieren können.

    Und nochwas: diese if-s tun nicht wirklich SO weh, selbst wenn sie drinbleiben (weil der Vergleichswert z.B. eine Variable ist, damit man die zur Laufzeit umsetzen kann oder sowas). Der Vergleich fällt ja meist gleich aus "nicht loggen", d.h. die Branch-Prediction kann das sehr gut handhaben.

    In ganz engen Schleifen ist sowas natürlich böse, aber in 99% des Codes schätze ich mal ziemlich egal.



  • Hallo,

    Logger5000 schrieb:

    Okay, anders formuliert:

    Kann ich den Typen der Nachricht vom Compiler überprüfen lassen mit irgendwie

    #if TYPE==BLA

    oder mussich das tatsächlich zur Laufzeit machen mit

    if(TYPE===BLA)

    habe mir jetzt nicht alles durchgelesen, aber so etwas:

    #define LP_DEBUG 1
    #define LP_WARNING 2
    #define LP_CRITICAL 4
    
    // enable warning and critical level
    #define TYP (LP_WARNING | LP_CRITICAL)
    
    #if TYP & LP_WARNING
      // Code
    #endif
    
    #if TYP & LP_DEBUG
      // Code
    #endif
    
    #if TYP & LP_CRITICAL
      // Code
    #endif
    

    funktioniert z.B.

    MfG,

    Probe-Nutzer


Anmelden zum Antworten