Logging für Anfänger
-
Hallo zusammen,
ich brauche ne kleine Funktion, welche ich so aufrufen will:
log("dies ist der "+3+". Test."+classeVar->getValue());
Das ganze will ich in eine Datei schreiben, wozu ich einen ofstream (<<) nutze. Irgendwie bin ich zu doof auf den Parameter für die Methode log() zu kommen. Nen Tipp?
Uwe
-
Das ist nicht möglich, sofern nicht einer übergebenen Werte ein selbstdefinierter Typ mit überladenem
operator+ist.Allerdings ist das ziemlicher Java-Stil. In C++ macht man sowas normalerweise über Streams oder ähnliche Klassen, die den
operator<<überladen. Zum Beispielstd::clog, das du auch auf Dateien umleiten kannst:std::clog << "dies ist der " << 3 << ". Test" << std::endl;Dann kannst du für eigene Typen selbst einen Stream-Operator definieren.
-
Hi,
ja das ist wohl Java Style ;). Das Problem ist, ich habe hier einen Simulator, welcher mir ein macro definiert für die Ausgabe. Da ich diese aber immer gleich haben will, wollte ich mir eine einfache Funktion, log, drumbasteln. Sonst findet man in der Logdatei ja nix wieder. Mh, dann muß ich wohl das Macro umbasteln. Irgendwie unschön, aber sonst fällt mir gerade nix ein.
Danke auf jeden Fall.
-
Du kannst auch eine Klasse drumbasteln, die den
operator<<überlädt. Wie sieht denn dein Makro aus und was wird als Makro-Parameter erwartet?
-
ich glaube, du mußt makros UND streams benutzen!
sowas wie#define LOG(bla) ofstream("log.txt",ios::append)<<time(0)<<' '<<__FILE__<<'('<<__LINE__<<')'<<' '<<bla;und später
LOG("file not found: "<<path<<'/'<<filename)
-
Also ich habe folgende Klasse (definiert durch den Simulator):
#include <iostream> #include <fstream> using namespace std; class DebugInfoWriter { private: static ofstream theFile; static string fileName; public: DebugInfoWriter(const string & fName); static void setDebugFileName(const string & fName); static ofstream & getStream(void); static void closeStream(void); };und folgendes Macro:
#define CASTALIA_DEBUG (!printDebugInfo)?(ostream&)DebugInfoWriter::getStream():DebugInfoWriter::getStream()Die Lösung von volkard funktioniert ja wieder nur für ne bestimmte anzahl ab vars, aber nicht für elipsen, verschiedener types.
-
uwerothfeld schrieb:
Also ich habe folgende Klasse
schon klar. das würde bei mir sein
#define VOLKARDUS_LOG ofstream("log.txt",ios::append)Die Lösung von volkard funktioniert ja wieder nur für ne bestimmte anzahl ab vars, aber nicht für elipsen, verschiedener types.
theoretische grenzen gibts bestimmt, aber ich weiß jetzt nicht, ob die in der praxis stören. praktisch ist, daß ich das logging auch ausschalten kann mit
#define LOG(bla) ;und dann die teuren aufrufe wie in
LOG("FreeDiskSpace: "<<getFreeDiskSpace())kostenlos werden.
blöd ist aber
LOG(foo(a,b))ob da dafür
LOG((foo(a,b)))geht?
-
uwerothfeld schrieb:
Die Lösung von volkard funktioniert ja wieder nur für ne bestimmte anzahl ab vars, aber nicht für elipsen, verschiedener types.
Doch - das macht er ja in seinem Beispiel. Trotzdem finde ich das nicht die sauberste Lösung, aber wohl die einfachste.

Aber dein Makro hat ja nicht Function-Style. Du musst wohl hinten Stream-Operatoren anhängen. Was mir nicht gefällt, ist der Cast. Und etwas mehr Klammern wäre vielleicht sicherer.
-
Der "übliche" C++ Weg ist eigentlich ein Makro zu basteln, welches sich so verwenden lässt:
void foo() { LOG() << "test message" << 1 << ", " << 2 << ", " << 3; }Das lässt sich z.B. so machen:
class LogHelper : private boost::noncopyable { public: explicit LogHelper(char const* filename, size_t lineNumber) : m_filename(filename), m_lineNumber(lineNumber), m_isFlushed(false) { } template <class T> LogHelper& operator << (T const& t) { m_logStream << t; return *this; } bool IsFlushed() const { return m_isFlushed; } bool IsLogActive() const { return ...; // true wenn geloggt werden soll } void Flush() { std::cout << m_filename << " (" << m_lineNumber << "): " << m_logStream.str() << "\n"; m_isFlushed = true; } private: std::stringstream m_logStream; char const* m_filename; // wir brauchen hier kein std::string, da __FILE__ sowieso ein string-literal ist, den wir nicht kopieren müssen size_t m_lineNumber; bool m_isFlushed; }; #define LOG() for (LogHelper __logHelper(__FILE__, __LINE__); __logHelper.IsLogActive() && !__logHelper.IsFlushed(); __logHelper.Flush()) \ __logHelperNatürlich kann man das Ganze erweitern indem man z.B. verschiedenen Log-Channels erlaubt, Verbosity-Levels einführt etc. Lässt sich mit diesem System aber alles relativ einfach unterbringen. Auch funktioniert es so wie man es sich erwartet (d.h. auch in if-Abfragen ohne {}). Und der Overhead wenn nicht geloggt wird, ist relativ gering.
Vermutlich könnte man das ganze noch weiter für den "es muss nicht geloggt werden" Fall optimieren, aber für die meisten Anwendungen sollte das so vollkommen ausreichen.
----
Die Version oben erlaubt es dass Exceptions aus dem LOG() Makro rausfliegen, wenn z.B. kein Speicher mehr da ist, oder beim Schreiben ins Logfile irgendwas schief geht. Lässt sich aber auch relativ einfach umbauen, z.B. indem man im operator << und der Flush() Funktion ein try-catch einbaut, z.B. so:
(meistens will man ja nicht, dass Logging-Funktionen Exceptions werfen, da man die sonst in no-throw Funktionen/Code-Teilen nicht verwenden könnte, oder jedesmal selbst in ein try-catch stecken müsste... und man kann Fehler beim Logging sowieso meist nicht sinnvoll behandeln)template <class T> LogHelper& operator << (T const& t) { try { m_logStream << t; } catch (...) { m_broken = true; } return *this; } void Flush() { try { if (!m_broken) std::cout << m_filename << " (" << m_lineNumber << "): " << m_logStream.str() << "\n"; } catch (...) { } m_isFlushed = true; }
-
Hallo zusammen,
also ich finde es toll, dass ihr mir so ausführlich helft. das problem ist jedoch: ich nutze einen simulator! da existieren schon zig tausend zeilen code, wo das macro ebenfalls genutzt wird. da muß ich sauber in die gleiche datei schreiben. außerdem steh ich bissl unter zeitnot, und wollte mir das leben einfach bissl einfacher machen. von daher bleib ich bei der volkard lösung, das tut doch ganz schön. vielen dank auf jeden fall.

uwe
-
STRIKE!
