Design eines Loggers



  • SBond schrieb:

    // Variante B
    Log(INFO) << "die Variable X mit den Wert " << myInt << " ist ungueltig";

    Das ist die Variante die ich im Moment verwende. Und auch diese lässt sich als Makro umsetzen.
    Mit diversen Kunstgriffen im "Log" Makro kann man es sogar hinbekommen dass der "<< x << y << z" Teil nur ausgewertet wird wenn der Logger überhaupt aktiv ist. Das ist günstig wenn man an performancekritischen Stellen logging einbauen möchte, welches im Normalbetrieb allein durch die Auswertung der Argumente für die << Operatoren schon bremsen würde -- selbst wenn der << Operator dann sieht dass es nichts zu tun gibt und entsprechend sofort "return" macht.

    Und dadurch dass es sich um ein Makro handelt kannst du auch in dieser Variante __FILE__, __FUNCTION__ und __LINE__ mitgeben.

    Wie man das machen kann kannst du dir z.B. bei Boost.Log abgucken.



  • Kann man Variante B überhaupt threadsafe implementieren? Also das diese Zeile garantiert als Ganzes geloggt wird.



  • Sicherlich.
    Du <<st ja nicht nach cout sondern in ein Log-Message Objekt. Das dann zum Schluss als ganzes .submit()ed wird.



  • Aber wie stellt man den Schluss fest? Also den letzten Aufruf von operator<<



  • hustbaer schrieb:

    SBond schrieb:

    // Variante B
    Log(INFO) << "die Variable X mit den Wert " << myInt << " ist ungueltig";

    Das ist die Variante die ich im Moment verwende.

    dito

    hmmmmmm schrieb:

    Aber wie stellt man den Schluss fest? Also den letzten Aufruf von operator<<

    Im Destruktor des Proxys.



  • hmmmmmm schrieb:

    Aber wie stellt man den Schluss fest? Also den letzten Aufruf von operator<<

    mit ner for-Schleife

    #define Log(channel) \
        for (LogMessage message(channel); message.IsActive(); message.Submit()) \
            message.GetStream() // - hier wird dann Zeugs reingeshiftet
    

    message.IsActive() muss dabei true zurückliefern wenn die Message noch nicht submitted wurde und der Log-Channel aktiv ist.



  • auf jeden Fall vielen Dank für die Antworten. Ihr habt mir sehr geholfen 🙂



  • hustbaer schrieb:

    hmmmmmm schrieb:

    Aber wie stellt man den Schluss fest? Also den letzten Aufruf von operator<<

    mit ner for-Schleife

    #define Log(channel) \
        for (LogMessage message(channel); message.IsActive(); message.Submit()) \
            message.GetStream() // - hier wird dann Zeugs reingeshiftet
    

    message.IsActive() muss dabei true zurückliefern wenn die Message noch nicht submitted wurde und der Log-Channel aktiv ist.

    Durch was wird die Schleife abgebrochen? Anderer Thread, der den Stream ausliest?



  • Ich vermute, die Schleife wird entweder genau einmal, oder niemals ausgeführt. Anders ergibt es keinen Sinn. Man hätte auch if schreiben können, dann müsste man aber einen umschließenden Scope haben, damit die Variable message nicht sichtbar ist. Sehr pfiffig 😉



  • volkard schrieb:

    Durch was wird die Schleife abgebrochen? Anderer Thread, der den Stream ausliest?

    Dadurch dass Submit aufgerufen wird.

    hustbaer schrieb:

    message.IsActive() muss dabei true zurückliefern wenn die Message noch nicht submitted wurde und der Log-Channel aktiv ist.



  • Torsten Robitzki schrieb:

    Ich vermute, die Schleife wird entweder genau einmal, oder niemals ausgeführt.

    Genau.
    0x wenn der Channel inaktiv ist und 1x wenn er aktiv ist.

    Torsten Robitzki schrieb:

    Anders ergibt es keinen Sinn.

    Genau.

    Torsten Robitzki schrieb:

    Man hätte auch if schreiben können, dann müsste man aber einen umschließenden Scope haben, damit die Variable message nicht sichtbar ist.

    Naja, message ist ja in der for-Lösung auch sichtbar. Daher verwendet man in echt dann auch nicht message als Bezeichner sondern eher sowas wie _message_NX2KLQA7MXHE21YLAW5DSVPQN0 . Um die Wahrscheinlichkeit klein zu halten dass der User-Programmer den Bezeichner in seinem Programm verwenden will.
    Die for-Schleife verwendet man deswegen, weil man dadurch den Submit Aufruf im "i++" Teil unterbringen kann. Das ginge bei if nicht.

    Torsten Robitzki schrieb:

    Sehr pfiffig 😉

    Ja. Eiskalt von Boost.Log nachgemacht.
    (EDIT: Weil unklar formuliert: Ich hab das natürlich bei Boost.Log abgeguckt - die hatten das vorher 😃 /EDIT)



  • Nu muss ich meinen Proxy löschen, deine Variante ist hübscher.
    😋



  • Naja dafür kannst du ne neue, schönere, bessere Klasse programmieren 😃

    Aber im Ernst, viel ändert sich dadurch ja nicht.

    Der vermutlich grösste Vorteil "meiner" Variante ist mMn. dass man unfertig befüllte Log-Messages erkennen kann. Also wenn beim "reinshiften" eine Exception fliegt. Lässt sich ja schön im Dtor der LogMessage * checken - quasi " if (!submitted) ThereWasAProblem(); ".
    Dann kann man z.B. ne spezielle Meldung rausloggen - evtl. mit dem unvollständigen Message-Text. Oder das Programm abbrechen. Bzw. vermutlich auf jeden Fall mal assert sagen, weil Exceptions beim Zusammenbasteln ner Log-Ausgabe sind ja normalerweise sehr unerwünscht.

    *: Name verbesserungswürdig - macht ja mehr als nur "message sein"


Anmelden zum Antworten