Gibs Sprachfeatures fuers Logging?



  • Logging kostet Performance. Wie hier gesagt wurde, ist im Debugging oder Testing ein Logging sehr nützlich. Bei Desktop-Anwendungen kann man vielleicht noch eine "erste Zeit lang" Logging betreiben. Auf einem Server der mit Anfragen befeuert wird und maximale Leistung bringen soll, ist es im produktiven Einsatz nicht hilfreich.

    Da finde ich dann das Log4J schon nicht schlecht, wo ich Debug-Levels habe. D.h. ich kann im produktiven Einsatz den Level so ändern, das nur noch das wichtigste aufgezeichnet wird... z.B. Fehlermeldungen.

    Ich mache das übrigens so:

    #ifdef _DEBUG
        std::clog << "Meine Debug-Info";
    #endif // _DEBUG
    

    Sehr spartanisch, aber nützlich. 😉



  • Logging kostet Performance. Wie hier gesagt wurde, ist im Debugging oder Testing ein Logging sehr nützlich. Bei Desktop-Anwendungen kann man vielleicht noch eine "erste Zeit lang" Logging betreiben. Auf einem Server der mit Anfragen befeuert wird und maximale Leistung bringen soll, ist es im produktiven Einsatz nicht hilfreich.

    Wo ist das Problem, beim mySQL Server kann man ebenfals Loging ein und ausschalten wie man lustig ist. Sowas koennte eine VM ganz gut optimieren, indem es einfach das Loging ganz entfernt, wenn es feststeht das loging nie benutzt wird.

    In Java verwende ich die Loging Klasse von der JRE, gefaellt mir ganz gut, nur wuerde es wirklich besser sein sowas in die Sprache zu integrieren. Zum einen koennte man dann den Preprozessor weglassen (und damit sich etliche Nachteile ersparen) und der Compiler koennte einen dabei auch unterstuetzen. Auch koennte der Compiler Loging automatisieren (zum Beispiel bei Exceptions, bei ein/austritten aus/in Methoden oder beim Speichermanagment).

    Ebenso ist ein Loging beim fertigen Produkt nicht zu unterschaetzen. Wenn was beim Kunden schiefgeht, kann man gleich nachvollziehen was er gemacht hat und was dabei schiefgegangen ist. Klar macht man bei einem zeitkritischen Code kein Loging, da aber eh 90% des Codes fuer die Perfomance irrelevant ist, macht es nichts aus dort ein "if" zusaetzlich zu haben.



  • Sehe ich genauso, 90% der Zeit warten normale Desktop-Programme auf Input vom Benutzer, was spricht da gegen ein gutes Logging.

    Bei uns wird bei Auftreten einer Exception dem Kunden automatisch offeriert das Log-File vollautomatisch an uns zu versenden. Ein kleiner Kommentar noch in eine TextArea und wir haben bereits die Möglichkeit den Fehler nachzuvollziehen und zu fixen. Gut, wir haben es in erster Linie auch mit Kleinkunden zu tun und der gute Kundenkontakt ist unser großer Vorteil. Aber auch große Firmen können mit gutem Logging viele Debug-Stunden einsparen. Kommt doch etwas mehr als "es ist abgestürzt" als Feedback.

    MfG SideWinder



  • Aber warum sollte man fürs Loggen extra solche Sonderzeichen in die Sprache einbauen?

    log(VERBOSE, "Hallo") tuts auch überall. Es wäre höchstens schön wenn in der Standard-Sprachbibliothek solche Funktionen vorhanden wären, dann könnten Editoren die Zeile auch hervorheben, einklappen, oder sonstwas.



  • DEvent schrieb:

    Ich dachte eher an echte Sprachfeatures in einer Sprache fuer das Logging. Es wundert mich aber wieso es nicht in modernen Sprachen implementiert. Scheint Logging doch nicht so wichtig zu sein?

    Warum sollte man daraus ein Sprachfeature machen? Das passt doch gut in eine Funktion oder in ein Macro.



  • log(VERBOSE, "Hallo")

    aber wenn man in dem string noch variablen hat und die vorher per stringstream zusammen bauen muss wirds eckelig



  • verbose schrieb:

    log(VERBOSE, "Hallo")

    aber wenn man in dem string noch variablen hat und die vorher per stringstream zusammen bauen muss wirds eckelig

    Deswegen nimmt man ja idr. ein Macro oder printf-Style-Formatierung.



  • das is ja eher ein allgemeines Problem, wie man die Ausgaben formatiert.



  • Hier wird auf die zahlreichen Nachteilen des Präprozessors hingewiesen. Sicher hat der Präprozessor seine Nachteile, aber gerade beim Logging kann er die angesprochenen hässlichen Dinge verbergen ohne es gleich in die Sprache zu integrieren. Schauen wir uns doch mal so ein mögliches Log-statement mit allen Schmakazien mal an. Ich habe das Beispiel des original Posters mal ein wenig ausgebaut:

    inline static Logger& getLogger()
    { static Logger logger = 0;
      if (logger == 0)
        logger = Logger.createLogger("project1.modul17.myclass");
      return logger; }
    
    // ...
    if ( logger.getLevel() > Level.DEBUG ) { logger.getOStream() << "der Wert ist " << a; }
    

    logger.getLevel() sei eine inline-Methode, so daß sich die Entscheidung, ob etwas ausgegeben wird auf ein Vergleich zweier ganzer Zahlen reduziert. Das geschieht zur Laufzeit, so daß das Logging über eine Konfigurationsdatei gesteuert werden kann.
    Das angesprochene Problem mit der Formatierung habe ich hier durch einen std::ostream gelöst. Das ist sehr billig, da das nur ausgeführt wird, wenn logging auch aktiviert ist.
    Das ganze ist natürlich sehr unschön. Das gebe ich zu. Aber glücklicherweise bietet uns diese grossartige Programmiersprache C++ doch eine Lösung dafür: den Prärpozessor. Wir definieren also ein paar Makros:

    #define log_define(clazz) inline static Logger& getLogger() \
    { static Logger logger = 0; \
      if (logger == 0) \
        logger = Logger.createLogger(clazz); \
      return logger; }
    #define log_debug(expr) if ( logger.getLevel() > Level.DEBUG ) { \
      logger.getOStream() << expr; }
    #define log_info(expr) if ( logger.getLevel() > Level.INFO ) { \
      logger.getOStream() << expr; }
    #define log_warn(expr) if ( logger.getLevel() > Level.WARN ) { \
      logger.getOStream() << expr; }
    #define log_error(expr) if ( logger.getLevel() > Level.ERROR ) { \ 
      logger.getOStream() << expr; }
    

    Das Codebeispiel reduziert sich damit auf:

    log_define("project1.modul17.myclass")
    // ...
    log_debug("der Wert ist " << a);
    

    Schön kompakt und lesbar. Ein Programm mit deaktivierten Logging läuft fast genauso schnell, wie ohne. Und wenn nun wirklich das letzte herausgeholt werden muß, dann werden die Markos einfach durch leere Definitionen ersetzt. Also ich finde den Präprozessor für solche Anwendungen durchaus empfehlenswert.
    Das oben beschriebene hat noch ein paar kleine Probleme, die aber lösbar sind. Ich habe das ganze, wie LordJaxom bereits erwähnt hat in meiner Open-Source-Bibliothek cxxtools veröffentlicht.

    Gruß

    Tntnet



  • @tntnet:

    Um nochmal auf Deine erste Antwort zurückzukommen, natürlich sollst Du nicht nachträglich irgendwas ändern. Ich benutze das System ja selbst. Ich wollte nur auf die möglichen Nachteile des Präprozessors hinweisen.

    Da ich außerhalb des Logging äußerst selten Bezeichner mit Namen log_* wähle, ist es hier in Realworld-Code auch noch nie zu Konflikten gekommen.

    Falls es wirklich mal zu Konflikten kommen sollte, könnte man allerdings immernoch den Vorschlag aufgreifen, die Makros als CXXTOOLS_LOG_* zu definieren und ein zusätzliches Include bereitzustellen, welches die alten Makros bei Bedarf hinzudefiniert.



  • Es wäre gut, wenn die Parameter an die Log-Funktion lazy wären. Dann müsste der Ausdruck nur ausgewertet werden, wenn er auch geloggt wird, also das Log-Level hochgenug ist, Logging generell an ist, whatever.

    Eine Sprache, die by Name übergeben kann, würde es auch schon tun.



  • Helium schrieb:

    Es wäre gut, wenn die Parameter an die Log-Funktion lazy wären. Dann müsste der Ausdruck nur ausgewertet werden, wenn er auch geloggt wird, also das Log-Level hochgenug ist, Logging generell an ist, whatever.

    Eine Sprache, die by Name übergeben kann, würde es auch schon tun.

    Ein weiterer Grund für Makros. Und wenn Du meine Makros genau anschaust, wird der Ausgabeausdruck tatsächlich nur ausgeführt, wenn das Logging aktiviert ist.



  • Ich hab doch keinen Bock meine Anwendung neu zu übersetzen.



  • Helium schrieb:

    Ich hab doch keinen Bock meine Anwendung neu zu übersetzen.

    Wieso nicht? Übersetzt du immer im Release? 😮 Und selbst wenn: was kostet es dich denn? Mußt du irgendwie auf einem Fahrrad sitzen und den Stromgenerator für den Build-Prozess in Gang setzen? Bei mir geht eigentlich alles automatisch...



  • Ich hab mir einen Logger selbst gebaut... Der kritische Pfad ist saukurz, es ist garantiert, dass keine Daten verloren gehen...

    Der Sendevorgang besteht aus einer Zeile...



  • tntnet schrieb:

    #define log_define(clazz) inline static Logger& getLogger() \
    { static Logger logger = 0; \
      if (logger == 0) \
        logger = Logger.createLogger(clazz); \
      return logger; }
    #define log_debug(expr) if ( logger.getLevel() > Level.DEBUG ) { \
      logger.getOStream() << expr; }
    #define log_info(expr) if ( logger.getLevel() > Level.INFO ) { \
      logger.getOStream() << expr; }
    #define log_warn(expr) if ( logger.getLevel() > Level.WARN ) { \
      logger.getOStream() << expr; }
    #define log_error(expr) if ( logger.getLevel() > Level.ERROR ) { \ 
      logger.getOStream() << expr; }
    

    Das ist ja der Horror-Trip und der wichtigste Grund wieso man den Preprozessor rauswerden und begraben sollte. Mach doch gleich die Loger-Klasse als Define-Macro rein 👎 .

    rüdiger schrieb:

    Warum sollte man daraus ein Sprachfeature machen? Das passt doch gut in eine Funktion oder in ein Macro.

    Wer lesen kann (naja...)

    Devent schrieb:

    Zum einen koennte man dann den Preprozessor weglassen (und damit sich etliche Nachteile ersparen) und der Compiler koennte einen dabei auch unterstuetzen. Auch koennte der Compiler Loging automatisieren (zum Beispiel bei Exceptions, bei ein/austritten aus/in Methoden oder beim Speichermanagment).

    Naja wird ein Traum bleiben, Loging zu automatisieren und zu standardisieren. 😞



  • Artchi schrieb:

    Helium schrieb:

    Ich hab doch keinen Bock meine Anwendung neu zu übersetzen.

    Wieso nicht? Übersetzt du immer im Release? 😮 Und selbst wenn: was kostet es dich denn? Mußt du irgendwie auf einem Fahrrad sitzen und den Stromgenerator für den Build-Prozess in Gang setzen? Bei mir geht eigentlich alles automatisch...

    Du stellst dir das komisch vor. Versetz dich mal in die Lage eines Entwicklers, der dein Produkt benutzt. Dieser muss also, wenn er ein höheres Logging Level haben will, dein Produkt neu übersetzen. Bevor ich das tun würde, hätte ich mir a) eine Alternative gesucht oder b) mir eine Alternative entwickelt, denn deine Vorstellung von Logging-Konfiguration ist in jeder Hinsicht geradezu weltfremd.



  • es gibt ja auch zwei arten von log-meldungen: die für die debug-version und die für den kunden.

    aber für beides braucht man keine sprachfeatures wie devent sie vorschlägt.



  • Man kann mit den Makros sehr leicht das Logging so konfigurieren, dass es im Build gar nicht (mehr) auftaucht, oder man den Log-Level zur Laufzeit beliebig einstellen kann.
    Verstehe gar nicht warum sich hier so viele am Präprozessor aufhängen, es gibt nunmal kein Sprachfeature, folglich muss man einen anderen Weg gehen der möglich ist.

    Und dass ein Präprozessor sinnvoll ist zeigen ja Präprozessoren für andere Sprachen, die geschrieben wurden, weil diese Sprachen, im Gegensatz zu C oder C++, eben keinen besitzen.



  • lolz schrieb:

    Und dass ein Präprozessor sinnvoll ist zeigen ja Präprozessoren für andere Sprachen, die geschrieben wurden, weil diese Sprachen, im Gegensatz zu C oder C++, eben keinen besitzen.

    Antithese: Die wurden von frustrierten C- oder C++-Programmierern geschrieben, weil diese damit arbeiten mussten und nicht umdenken wollten.


Anmelden zum Antworten