Einen Datenstream auch bei einer Execption sicher schreiben

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Di Feb 02, 2010 7:04 pm

Hallo aus Südamerika,

ich stehe mal wieder vor einem Problem, bei dem ich einen Denkanstoß brauche. Vor kurzem habe ich unter Projekte meine Logfileklasse vorgestellt. Erstmal ein bisschen Code um das Problem zu verdeutlichen:

Code: Alles auswählen

int sqlite::check(int ret_value)
{
    log.add("Entering check()");
    switch(ret_value)
    {
        case DATATYPE_NOT_HANDLED : log.add("SQL-W: Datatype not handled!");
                                    throw std::runtime_error(
                                      "Wrapper Error: Datatype not handled!");
                                    break;

        case DATATYPE_UNKNOWN     : log.add("SQL-W: Datatype unknown!");
                                    throw std::runtime_error(
                                          "Wrapper Error: Datatype unknown!");
                                    break;

        case SQLITE_OK            : log.add("SQL-W: SQLITE_OK");
                                    return WRAPPER_OK;
                                    break;
        default                   : log.add("SQL-W:SQL-Error:" +
                                             *sqlite3_errmsg(db_handle));
                                    throw std::runtime_error(
                                               sqlite3_errmsg(db_handle));
    }
    log.add("Leaving check()");
    return WRAPPER_ERROR;
}

Dieser Code stammt aus der aktuellen Version meiner SQLitewrapper Klasse. Mein Problem besteht jetzt darin, das zwar die throw Anweisungen problemlos befolgt werden, aber die Fehlermeldung die über log.add geschrieben werden soll, nicht mehr in der Datei landet.

Die aktuelle Version von log.add sieht so aus:

Code: Alles auswählen

void logfile::add(const std::string &input)
{
    check_size();

    boost::posix_time::ptime pt =
                            boost::posix_time::second_clock::local_time();

    logfile::logstream << input << " "
                       << boost::posix_time::to_simple_string(pt)
                       << std::endl;
}
Hat jemand eine Idee, wie ich dieses Problem umgehen kann? Es wäre ja schließlich sehr hilfreich, wenn die Fehlermeldungen in der Logdatei stehen würden.

Gruß Bebu
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von cloidnerux » Di Feb 02, 2010 7:13 pm

Dieser Code stammt aus der aktuellen Version meiner SQLitewrapper Klasse. Mein Problem besteht jetzt darin, das zwar die throw Anweisungen problemlos befolgt werden, aber die Fehlermeldung die über log.add geschrieben werden soll, nicht mehr in der Datei landet.
Welche log.add Anweisung? Vor oder nach dem throw?
Und du solltest auch noch einen try/catch-Block in deiner "add" funktion einbauen.

Auch hatte ich schon, das ifstream mit folgendem Aufruf nicht funktionierte:

Code: Alles auswählen

ifstream >> var;
Vielleicht solltest du das mal mit Write oder so Probieren.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Di Feb 02, 2010 7:25 pm

cloidnerux hat geschrieben:Welche log.add Anweisung? Vor oder nach dem throw?
Und du solltest auch noch einen try/catch-Block in deiner "add" funktion einbauen.
Ich meine die log.add vor dem throw, also müsste diese Funktion sauber ausgeführt werden. Deshalb will sich mir das mit dem Try Catch in einer Funktion, die vor dem throw steht, nicht so recht erschließen. Aber ich kann es mal versuchen. Das mit dem Write könnte schwierig werden, weil ich die Boost Variante der Streamklassen benutzte, ist also nicht einfach so austauschbar ohne große Teile umzuschreiben.
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Di Feb 02, 2010 10:22 pm

Also hier eine Zwischenmeldung: Der Try Catch Block in der Add Funktion hat erwartungsgemäß nicht funktioniert. Dieser Fehler ist ohnehin merkwürdig, weil noch ein Teil im Log auftaucht, der bei einer Exception gar nicht auftauchen dürfte, der korrekte Teil aber überhaupt nicht funktioniert. Gibt es eine Möglichkeit ungepuffert in einen ofstream zu schreiben?
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Dirty Oerti » Di Feb 02, 2010 10:40 pm

Hehe. Ich denke es handelt sich hierbei um das selbe Problem wie bei der Fehlersuche mit Hilfe von Testausgaben. Sicher bin ich mir aber nicht, da ich den internen Ablauf deines Logsystems nicht kenne.
Und zwar:

Code: Alles auswählen

cout << "Ich bin ein Test";
// Kritischer Fehler direkt in der hier folgenden Anweisung (oder auch 2/3 Anweisungen weiter)
Bei diesem dargestelltem Fall wird die Ausgabe nicht mehr getätigt. Denn durch den kritischen Fehler beendet sich das Programm, bevor dessen Ausgaben auf die Standardausgabe gebracht wurden (die Ausgaben also synchronisiert wurden).
Und sobald ein Programm beendet ist gibt es auch nichts mehr aus.
Die Folge: Noch nicht ausgegebenes wird auch nicht mehr ausgegeben.

Um das zu umgehen muss man die Ausgabe "manuell" synchronisieren.

Die einzig mir dazu bekannte Lösung ist, einfach ein "\n" ans Ende anzuhängen.
Das führt - zumindest bei cout / cerr - dazu, dass die Ausgabe synchronisiert werden und somit auch dargestellt werden, wenn das Programm unmittelbar danach hops geht.
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Mi Feb 03, 2010 2:18 am

Danke für den Tipp, aber den habe ich als erstes ausprobiert. Weder ein \n noch ein endl ändern etwas.
Ich denke eher, das es ein Problem in der Stackauflösung ist, und die Funktionen nicht in der exakten Reihenfolge abgebaut werden. Ich bin mir nicht ganz sicher, aber wenn ich das mit den ungehandelten Exceptions richtig verstanden habe, werden nacheinander alle aufgerufen Funktionen abgebaut, bis ein catch gefunden wird, das den Fehler behandelt. Wird keiner gefunden, schmiert das Programm ab.

Ich habe drei Funktionen. Die äußerste ruft die Checkfunktion aus dem ersten Post auf. Die Checkfunktion ruft die Logfunktion auf und anschließend wird über throw eine Exception ausgelöst. Die Logfunktion vor dem throw kommt in der Datei gar nicht an. Andererseits wird der Logeintrag, der am Schluss der äußersten Funktion steht zu 70 % Prozent geschrieben, es fehlen die ersten 4 oder 5 Buchstaben, der Rest kommt an. Dieses Bild stimmt so überhaupt nicht mit der Theorie, die ich gelernt habe überein. Auf Wunsch kann ich euch das ganze Projekt hier reinstellen, das sind allerdings 5 Quellcodedateien und 4 Header, in die man sich erstmal hineinarbeiten muss. Ihr könnt auch gerne das Git Archiv haben, ich habe nur keinen Webspace zur Verfügung um es hochzuladen.

Das ist ein Problem das ich überhaupt nicht nachvollziehen kann, vielleicht hat einer von den Profis ja mehr Ahnung davon.
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Benutzeravatar
Kerli
Beiträge: 1456
Registriert: So Jul 06, 2008 10:17 am
Wohnort: Österreich
Kontaktdaten:

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Kerli » Mi Feb 03, 2010 11:32 am

Ich glaub es wäre das einfachste wenn du ein vollständig kompilierbares Archiv zur Verfügung stellst. Welchen Compiler verwendest du denn eigentlich?
"Make it idiot-proof and someone will invent an even better idiot." (programmers wisdom)

OpenGL Tutorials und vieles mehr rund ums Programmieren: http://www.tomprogs.at

Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Do Feb 04, 2010 6:29 pm

Sorry das mit dem vollständig kompilierbaren Archiv ist ein bisschen schwierig umzusetzen, da müsste ich die komplette Boost-Library mit hochladen. Ich benutze den GNU GCC Compiler unter Code-Blocks. Leider habe ich von Makefiles keine Ahnung, ich habe es nur als Projektdatei zur Verfügung. Im Anhang findest du den Code samt Projektdateien. Um es kompilieren zu können, brauchst man einige kompilierte Boostbestandteile, genau genommen date_time, filesystem und system. Die Linkerpfade müssen angepasst werden, die werden nicht übereinstimmen, weil ich die Boost unter meinem Homeverzeichnis liegen habe. Außerdem ist noch die libsqlite3 samt Header nötig. Unter Ubuntu kann man sie direkt über den Packetmanager installieren oder das Archiv unter http://www.sqlite.org/download.html herunterladen. Erfordert leider ein paar Umstände, aber da hängen mittlerweile doch ein paar fremde Librarys mit im Projekt.

In der Main wird absichtlich ein Fehler erzeugt, der eine Exception wegen eines ungültigen SQL-Kommandos auslöst. Das Programm legt automatisch einen Unterordner log an, dort sind die Logs zu finden. Beim Durchsehen der Log, wird der Fehler offensichtlich, zumindest bei mir.

Gruß Bebu
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Benutzeravatar
Kerli
Beiträge: 1456
Registriert: So Jul 06, 2008 10:17 am
Wohnort: Österreich
Kontaktdaten:

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Kerli » Mo Feb 08, 2010 6:37 pm

Bebu hat geschrieben:Sorry das mit dem vollständig kompilierbaren Archiv ist ein bisschen schwierig umzusetzen
Das hab ich eh nicht gemeint. Ich wollte nur den gesamten Code mit irgendwas das mir das zu einer Executable bauen kann. Die Bibliotheken hab ich sowieso drauf. Und wozu gibt es apt-get :P

An deinem Problem sind zwei Sachen schuld. Erstens verstehe ich folgenden Code nicht so ganz:

Code: Alles auswählen

default: log.add("SQL-W:SQL-Error:" +
                         *sqlite3_errmsg(db_handle));
Du addierst zur Adresse des ersten String den nach 'int' konvertierten Wert des ersten Zeichen der Fehlermeldung. Da beginnt die Ausgabe dann eben zufälligerweise mitten in einem deiner anderen konstanten Strings ;) Richtig wäre es so:

Code: Alles auswählen

default: log.add(std::string("SQL-W:SQL-Error:") +
                         sqlite3_errmsg(db_handle));
Und das zweite Problem ist das eine nicht aufgefangene Exception undefiniertes Verhalten hervor ruft, und bei mir dabei zum Beispiel der Destruktor der sqlite Klasse nicht mehr aufgerufen wird. Ich bau dafür zb in der main Funktion immer einen try/catch Block ein der einfach alle unbehandelten Exceptions auffangt und die Fehlermeldung nach std::cerr ausgibt. Somit ist sichergestellt das der Stack immer korrekt abgebaut wird.
"Make it idiot-proof and someone will invent an even better idiot." (programmers wisdom)

OpenGL Tutorials und vieles mehr rund ums Programmieren: http://www.tomprogs.at

Benutzeravatar
Bebu
Beiträge: 562
Registriert: Mi Okt 21, 2009 6:19 pm
Wohnort: In der Nähe von Salzburg - Bin aber kein Österreicher!

Re: Einen Datenstream auch bei einer Execption sicher schreiben

Beitrag von Bebu » Mo Feb 08, 2010 7:47 pm

Vielen Dank an Kerli, es war tatsächlich der erste Fehler, jetzt funktioniert es so, wie es soll. Wäre ich aber selber nie draufgekommen. Das mit den ungehandelten Exceptions ist im Moment noch Absicht, aber das soll nicht so bleiben. Herzlichen Dank.
Wer immer nach dem Unerreichbaren jagt, der wird irgendwann auf die Schnauze fallen!

Antworten