cout, clog und cerr umleiten
-
Aloha und guten Morgen,
vorneweg: Der Titel ist ein wenig unglücklich gewählt. Mein Ziel ist mehr als umleiten, aber modifizieren war mir zu hoch gegriffen.
Aber, meine Situation:
Ich sitz hier vor einem Programm, in dem reichlich Gebrauch von cout, clog und cerr gemacht wurde. Das Problem, dass ich jetzt habe, ist, dass die Ausgaben ein klein wenig zu schnell über die Konsole rattern. Deswegen würde ich die gerne in eine Datei umleiten, damit ich mir die in Ruhe anschauen kann.Das ist jetzt weniger das Problem, über das Umleiten mittels rdbuf() bin ich mir im Klaren. Das hat nur 2 kleinere Folgeprobleme:
1. Wenn ich cout, clog und cerr auf die gleiche Datei umleite, dann weiß ich nicht mehr, von wo die Ausgabe eigentlich kommt.
2. Wenn ich cout, clog und cerr auf 3 unterschiedliche Dateien umleite, verliere ich chronologische Informationen.
Ich würde am liebsten also Variante 1 nehmen und alle Ausgaben in eine Datei leiten. Wie gesagt, weiß ich, wie das mit rdbuf() zu erreichen wäre. Jetzt hätte ich es aber noch gerne, wenn die Ausgaben noch modifiziert werden. Damit meine ich, dass z.B. ein
std::cout << "eine normale Ausgabe" << std::endl; std::clog << "ein Logeintrag" << std::endl; std::cerr << "ein Fehler" << std::endl;in der Datei als
OUTPUT: eine normale Ausgabe LOG: ein Logeintrag ERROR: ein Fehlergeschrieben werden.
Ich hab mich deswegen mal durch die C++ Referenz gegraben und bin auf die Funktion tie()der Streams gestoßen. Nur scheint die Funktion nicht das zu machen, was ich erwartet hatte.
Deswegen meine Fragen an euch:
Geh ich das Ganze falsch an?
Gibts doch einen Weg über rdbuf()? (Mir ist keiner eingefallen)
Und ist das überhaupt möglich?Danke schonmal, hoffentlich sind einige von euch Montagmorgens fitter als ich

Gruß
Shelling
-
Und wenn Du mit mkfifo drei named pipes machst, ein Lausch-Programm startest, das an allen drei Pipes lauscht und jede reinkommende Zeile in die Log-Datei schreibt mit Zeitstempel und Herkunftspipe, und dann das zu untersuchende Programm mit in die named Pipes umgeleiteten Ausgaben?
-
Das wäre wohl eine Möglichkeit, allerdings wollte ich eigentlich Plattformunabhängig bleiben (zumindest sieht es so aus, als wäre mkfifo unter Windows nicht ohne weiteres vorhanden) und nicht extra ein zweites Programm starten.
Ich hatte gehofft, es gäbe dafür eine Möglichkeit, eine eigene stream Klasse zu erstellen und den operator<< zu überschreiben. Hat leider nicht das gewünschte Ergebnis gebracht.
Was mir noch eingefallen ist, was ich allerdings auch ein wenig "dreckig" finde:
Ich erstell mir 3 Klassen, cout_buf, clog_buf und cerr_buf, alle 3 abgeleitet von std::streambuf und kapsel darin einen filebuf auf meine Logdatei. Wenn ich dann noch die virtuelle Funktion "xsputc()" in meinen 3 Klassen überschreibe, sollte ich theoretisch das gewünschte Ergebnis bekommen.
Bevor ich das angehe, spricht irgendwas gegen diese Idee? (Klingt fast so ähnlich wie die von volkard, nur programminterner)
-
Darf es quick&dirty sein?
#define cout log_out << "COUT " << timestamp() << ": "Ansonsten: Es sollte eigentlich schon möglich sein, deine eigenen Streambuffer mit timestamp und Umleitung zu schreiben und diese an cout, cerr und clog zu binden. Ist aber sicherlich ein ganz schöner Aufwand, im Gegensatz zu der Variante oben.
-
SeppJ schrieb:
Es sollte eigentlich schon möglich sein, deine eigenen Streambuffer mit timestamp und Umleitung zu schreiben und diese an cout, cerr und clog zu binden. Ist aber sicherlich ein ganz schöner Aufwand, im Gegensatz zu der Variante oben.
es gibt schon was ähnliches hier im Forum - mit ein paar Änderungen könntest Du diesen Code nutzen.
Gruß
Werner
-
Werner Salomon schrieb:
SeppJ schrieb:
Es sollte eigentlich schon möglich sein, deine eigenen Streambuffer mit timestamp und Umleitung zu schreiben und diese an cout, cerr und clog zu binden. Ist aber sicherlich ein ganz schöner Aufwand, im Gegensatz zu der Variante oben.
es gibt schon was ähnliches hier im Forum - mit ein paar Änderungen könntest Du diesen Code nutzen.
Gruß
WernerAch, jetzt hatte ich gerade ein eigenes Beispiel entwickelt. Eigentlich gar nicht so schwer (mit den richtigen Hilfsmitteln
) und eine nette Übung:#include <boost/iostreams/device/file.hpp> #include <boost/iostreams/filtering_stream.hpp> #include <boost/iostreams/filter/line.hpp> #include <string> #include <ctime> namespace io = boost::iostreams; class prefix_and_timestamp : public io::line_filter { public: explicit prefix_and_timestamp(const std::string& prefix): prefix(prefix) {} private: std::string prefix; virtual string_type do_filter(const string_type& line) { std::time_t rawtime; std::time ( &rawtime ); struct tm * timeinfo = localtime(&rawtime); char timestamp [80]; strftime (timestamp,80,"%x %X",timeinfo); return prefix + timestamp + std::string(": ") + line; } }; int main() { io::filtering_ostream cout; cout.push(prefix_and_timestamp("COUT ")); cout.push(io::file_sink("my_log_file.txt")); cout << "Hello World\n"; }