Thread Safe Singleton - so richtig? noch tips?
-
Ich stelle mal eine einfach Frage:
gehört Logging zu den Aufgaben einer daten verarbeitenden Klasse?
Ich kann verstehen, dass man Logging an bestimmten Stellen braucht, aber Debug-Logging? Fehler-Loging? Gibt es dafür nicht debugger, assert und Exceptions? Wird hier nicht ein paralleles debugging Framework hochgezogen?
-
@otze
Debug mal einen Fehler der beim Kunden draussen schon passiert ist mit einem Debugger oder Assertions.
Selbst Fehler die "schlecht aber doch irgendwie" reproduzierbar sind findest du schlecht mit nem Debugger, weil du das Programm halt nicht hunderte Stunden im Debugger beobachten kannst.
Assertions und Debug-Traces helfen da nicht viel.Ausführliche Log-Ausgaben dagegen schon. Wie man dazu dann sagt (debug, verbose, ...) ist egal, wichtig ist dass viel geloggt wird. Und das schliesst natürlich diverse Hilfsklassen mit ein deren primäre Aufgabe es natürlich nicht ist Log-Messages zu generieren.
Deswegen verwendet man ja auch gerne flexible Logging-Frameworks, wo man Log-Ausgaben je nachdem wo sie herkommen und wie wichtig sie sind selektiv ein- oder ausschalten kann. Bzw. auch mal in eigene Files routen oder was auch immer.
-
otze ist Akademiker, der hat nichts mit Kunden zu tun
-
hustbaer schrieb:
Ausführliche Log-Ausgaben dagegen schon.
Manchmal versagt der Debugger. Das hatte ich schon oft. Das einfach keine Fehlermeldung kommt - er beendet sich von selbst. Oder der Stacktrace ist unbrauchbar. Nein, alle Pfade stimmen. Der Debugger funktioniert nicht.Früher habe ich Checkpoints benutzt. Also
std::cout << "CHECK! ... \n"; // ... steht für eine Zahl o.ä.
Zwischen verschiedene Statements in verdächtigen Bereichen geschrieben, wenn irgendwo ein merkwürdiger Fehler auftrat. Dann den kompletten Stacktrace langsam rekonstruiert. Dann ist mir aufgefallen, dass ich auch einfach richtig loggen könnte. Daraus habe ich angefangen, dass stärker zu machen. Einfach den aktuellen Task loggen, bei vielen Funktionen. Geht natürlich nur bei relativ kleinen Projekten, bei größeren würde man vielleicht den überblick verlieren, da müsste man nur größere "Dinge" loggen.
Bei einem solchen Problem sieht man dann sofort, wo genau der Fehler auftrat. Falls man wirklich so penibel alles mit seinen Logs "kommentiert", sieht man sich im Endeffekt nur 20 "verdächtige" LoCs an.
Natürlich habe ich aber nie eine größere Applikation entwickelt, wo tatsächlich der Log auch als Report an die Entwickler gesendet wird o.ä., daher ist das meine Stubenerfahrung.
-
Sone schrieb:
Der Debugger funktioniert nicht.
Kann nicht sein. Du verwendest den Debugger falsch.
Der Post von hustbaer ist so zu verstehen: Wenn ein Debugger verfügbar ist, dann ist das die erste Wahl.
Nur ist es manchmal nicht möglich, z.B. wenn es sich um einem Kunden handelt mit einem sehr komplexen Setup bei dem es nach mehreren Tagen Laufzeit unter bestimmten Umständen zu einem Performance-Bug kommt. Dann ist Logging die beste Alternative.
-
gdb schrieb:
Sone schrieb:
Der Debugger funktioniert nicht.
Kann nicht sein. Du verwendest den Debugger falsch.
Nein, das kann nicht sein. Ich starte den Debugger, es ist der richtige, und das Programm beendet sich von selbst. Das ist nicht anders zu erklären.
-
@gdb
Muss nicht unbedingt ein Performance-Problem sein.
Manchmal tut ein System im Livebetrieb einfach nicht das was es soll, und keiner weiss wieso. Und keiner weiss wie man es nachstellen kann - ausser beim Kunden im Livebetrieb drauf zu warten dass es wieder passiert.Wenn das System crasht könnte man ja noch Crashdumps schreiben. So bleiben einem nur Logfiles. Logfiles sind gut.
Sone schrieb:
hustbaer schrieb:
Ausführliche Log-Ausgaben dagegen schon.
Manchmal versagt der Debugger. Das hatte ich schon oft. Das einfach keine Fehlermeldung kommt - er beendet sich von selbst. Oder der Stacktrace ist unbrauchbar. Nein, alle Pfade stimmen. Der Debugger funktioniert nicht.Nimm MSVC und alles wird gut
Sone schrieb:
Dann ist mir aufgefallen, dass ich auch einfach richtig loggen könnte. Daraus habe ich angefangen, dass stärker zu machen. Einfach den aktuellen Task loggen, bei vielen Funktionen. Geht natürlich nur bei relativ kleinen Projekten, bei größeren würde man vielleicht den überblick verlieren, da müsste man nur größere "Dinge" loggen.
Es gibt Logging-Libs die "info"/"verbose"/"debug" Messages welche nicht (sofort) ins Logfile geschrieben werden erstmal in einem per-Thread Puffer im RAM puffern. Und die gepufferten Messages dann bei Bedarf rausschreiben können. z.B. einfach vor jeder Fehlermeldung.
Ich hab' selbst noch nie mit sowas gearbeitet, aber ich denke dass das ein ziemlich cooles Feature ist. Genau für Situationen wo man viel loggen möchte, aber nicht will dass das Logfile dadurch total unübersichtlich/riesig wird.
-
Sone schrieb:
gdb schrieb:
Sone schrieb:
Der Debugger funktioniert nicht.
Kann nicht sein. Du verwendest den Debugger falsch.
Nein, das kann nicht sein. Ich starte den Debugger, es ist der richtige, und das Programm beendet sich von selbst. Das ist nicht anders zu erklären.
Was ganz normal ist, wenn das Programm sich einfach normal beendet. Da muss nicht der Debugger schuld sein.
-
Meine Crashreports haben mir auch nicht viel (manchmal halt nur) geholfen. Wenn im Release-Modus viel wegoptimiert wurde, bleibt einfach nicht immer das wichtige Detail übrig, an dem es scheitert. Da ist dann in irgendeiner Containertiefe oder einem QT-Modul ein Fehler, dann kommen 20 Assembler-Ebenen und dann ist man in der WinMain... Außerdem habe ich keine reproduzierbaren Fehler mehr (weil die reproduzierbaren alle raus sind), also hilft auch kein Loggen, das will man ja nicht auf Verdacht einfach immer anstellen. Da hilft dann eher schon der Screenshot, wo man evtl. einen Klick sieht. Da hilft mir das Loggen aber auch nicht weiter und in MT-Umgebungen wird es noch etwas unübersichtlicher, da muss man dann ja quasi per Thread loggen. Habe aber einen hohen Verschleiß an Threads, da hätte man ständig "Erstellt/Zerstört"-Meldungen.
Alles nicht so einfach.
-
Eisflamme schrieb:
Meine Crashreports haben mir auch nicht viel (manchmal halt nur) geholfen. Wenn im Release-Modus viel wegoptimiert wurde, bleibt einfach nicht immer das wichtige Detail übrig, an dem es scheitert. Da ist dann in irgendeiner Containertiefe oder einem QT-Modul ein Fehler, dann kommen 20 Assembler-Ebenen und dann ist man in der WinMain...
Source-Control-Infos in the PDB Files reinschreiben, PDB Files + EXEn in einen Symbol Server, Symbol Server Pfad im VS eintragen -> schon kannst du die Crashdumps im Debugger verwenden als ob das Programm gerade frisch bei dir compiliert worden wäre.
Nix mit Disassembly angucken und rumraten, alles schön mit original Source Code.Außerdem habe ich keine reproduzierbaren Fehler mehr (weil die reproduzierbaren alle raus sind),
Na schön dass du an einem Programm arbeitest wo sich so wenig tut dass keine neuen Fehler mehr dazukommen. Was machst du dann die restlichen 7,5 Stunden/Tag?
also hilft auch kein Loggen, das will man ja nicht auf Verdacht einfach immer anstellen.
Na deswegen macht man logging idealerweise auch konfigurierbar. So dass man es bei Problemkunden weiter aufdrehen kann, und wenn der Fehler dann nochmal kommt, dann hat man detailiertere Logfiles.
Da hilft dann eher schon der Screenshot, wo man evtl. einen Klick sieht. Da hilft mir das Loggen aber auch nicht weiter und in MT-Umgebungen wird es noch etwas unübersichtlicher, da muss man dann ja quasi per Thread loggen. Habe aber einen hohen Verschleiß an Threads, da hätte man ständig "Erstellt/Zerstört"-Meldungen.
Alles nicht so einfach.
Es gibt auch Programme die keine GUI haben
-
hustbaer schrieb:
Ich hab' selbst noch nie mit sowas gearbeitet, aber ich denke dass das ein ziemlich cooles Feature ist. Genau für Situationen wo man viel loggen möchte, aber nicht will dass das Logfile dadurch total unübersichtlich/riesig wird.
Oh ja! Das hört sich interessant an.
Aber einfach puffern wie mit einem Ringbuffer und dann bei Fehlern nur die letzten Fünfzig Zeilen schreiben? So primitiv ist die Idee dann nicht. Hast du Links?
-
Sone schrieb:
Aber einfach puffern wie mit einem Ringbuffer und dann bei Fehlern nur die letzten Fünfzig Zeilen schreiben?
Wer schreibt? Bedenke, daß es Abkacker gibt, die nichts flushen.
Die eigene Anwendung sollte echt bei jedem Fehler flushen. Besser ist das wohl.
Und das macht lahm.
Optimalerweise hat man viel mehr Infos und Warnungen als Fehler. Die kann man gepuffert schreiben. Das war die Idee.Gibt viele Ideen dazu. Zum Beispiel auf einen anderen Rechner loggen, weil das Netz *viel* schneller als die lokale zeilenweise geflushte lokale Datei ist. Oder das eigene Programm startet ein zweites, was Log-Zeilen empfängt, gerne auch mit Handshake, und der Log-Empfänger kann voll schreiben oder Ringbuffer sein, egal, er kann rausschreiben, wenn das Hauptprogramm abkackt.
Muss aber sagen, das waren nie nie meine Probleme. Ich hatte immer nur Probleme, rauszufinden, welche Code-Zeile dran schuld ist, was ich für mich zufriedenstellend löse, indem ich den Debug-Logger anwerfe, der noch einen int für die Funktionsverschachtelungstiefe führt, und jede interessante Funktion schreibt als erste Tat eine Logzeile mit Funktionsnamen und den Aufruf-Parametern. Im Logfile wird je nach Verschachtelungstiefe halt eingerückt.
-
Sone schrieb:
Aber einfach puffern wie mit einem Ringbuffer und dann bei Fehlern nur die letzten Fünfzig Zeilen schreiben? So primitiv ist die Idee dann nicht. Hast du Links?
Doch, kann so primitiv sein.
Natürlich kann/sollte man es noch etwas verfeinern/tunen. z.B. indem man sicherstellt dass Zeilen nie doppelt geloggt werden.
Also den Fall
* 100 Events die nur gepuffert werden
* Fehler -> letzten 50 Zeilen schreiben
* Fehler -> letzten 50 Zeilen schreiben, wobei 49 schon beim letzten Fehler geschrieben wurden
entschärfen.Bzw. auch wenn man weiss dass ein Vorgang vollständig und 100% erfolgreich abgeschlossen wurde kann man dem Logger auch mitteilen dass er die gepufferten Log-Einträge jetzt vergessen kann und neu anfangen zu puffern. Damit nicht die ganzen Infos über das was eh funktioniert hat als "Vorgeschichte" eines Fehlers geloggt werden.
Ansonsten würde ich da nicht grossartig mehr rumfeilen. Man möchte ja nicht dass das Logging-Framework die Applikation lahmlegt, nur weil es meint mehr puffern zu müssen als für den RAM-Verbrauch "gut" ist.
=> Vielleicht sogar das Limit auf Byte statt Zeilen-/Event-Anzahl machen.@volkard
Ich sehe hier zwei verschiedene Fälle auf die man hin optimieren kann.
A: Programm crasht ganz böse und man will dass man danach noch brauchbare Daten hat.
B: Programm crasht nicht und verhält sich bloss nicht richtig, und man will rekonstruieren können warum.
Für Fall A sind Crash-Dumps was feines. Die kann man auch von einem externen "Überwacher"-Prozess schreiben lassen. Oder gleich vom OS.
Und für Fall B glaube ich dass (im RAM, ohne komplizierte Helper-Prozesse) gepufferte Log-Events eine feine Sache sind.