Logging über DLL-Grenzen hinaus
-
Hallo liebe Gemeinde,
ich habe mir einen einfachen kleinen Logger geschrieben, der einfach einen std::ofstream verwendet und zum formatieren nutze ich temporär std::ostringstream.
Jetzt entwickle ich ein Plugin für ein bestehendes Produkt, d.h. mein "Einstiegspunkt" ist selber in eine DLL. Aus dieser DLL heraus lade ich wiederum von mir entwickelte DLLs. In den von mir geladenen DLLs verwende ich aber das Logging aus meiner "Core"-DLL. Problem ist aber dass das logging in den von mir geladenen DLLs nicht funktioniert, d.h. es schreibt nichts in die Log-Datei.
Die Logging-Klasse ist ein Singleton und für ein einfacheres Handling nutze ich ein paar kleine Macros, alles in der "Core"-DLL definiert.Kann es sein das über die "DLL-Grenzen" hinaus das Stream-Objekt "ungültig" wird und es daher nix loggt? Es kommt auch kein Laufzeitfehler und Kompilieren tut es ebenfalls ohne Probleme. Die Logger Klasse wird auch exportiert.
Im Moment kompiliere ich alles noch mit dem MSVC9 es soll später aber auch mit GCC kompilierbar sein.
Hier noch ein paar kurze Listings um sich ein Bild machen zu können:
Ausschnitt Macro:
# define _LOG_IMPL(lvl, m, con) \ do { \ std::ostringstream __str_stream__; \ __str_stream__ << m << std::endl; \ util::Logger::instance().##lvl##(__str_stream__.str()); \ con("map2: %s", __str_stream__.str().c_str()); \ } while (0) # define LOG_TRACE(m) \ _LOG_IMPL(trace, m, Msg)Ausschnitt einer Methode aus der Implementierung des Loggers:
std::ostream& LoggerImpl::debug(std::string const& str) { _logStream << timestamp() << " [DEBUG]: " << str; return _logStream; }Die eigentliche Singletondefinition:
typedef Singleton< detail::LoggerImpl > Logger;Genutzt wird es dann einfach wie folgt, sowohl in der "Core" als auch in der von mir geladenen "Module" DLL.
LOG_INFO("load module: " << mod->name());Oder sollte ich vielleicht für jedes "Module" eine eigene std::ofstream Instanz im Logger erstellen?
Gut Schuß
VuuRWerK
P.S.: Falls das wichtig ist, die "Module" lade ich im "Core" via LoadLibrary/dlopen und GetProcAddress/dlsym.
[edit]
Was mir gerade noch einfiel. Der "con" Parameter im Logger Macro ist im übrigen ein Name einer Funktion von dem Produkt für das ich diese Module entwickle. Im obigen Beispiel "Msg" schreibt die Message zusätzlich auf eine Konsole was ich nutze um direkt etwas sehen zu können. Aber auch dies sehe ich nicht.
[/edit]
-
Derartige Makro-Hacks haben in C++ nichts zu suchen!
-
Funktionen, enum und/oder const Variablen als Konstanten nutzen anstelle von Macros.
Aber, mein derzeitiges Verhältnis zwischen Macros und C++ Quellcode liegt bei 1:100 (ca. 100 Zeilen Macros zu 10.000 Zeilen C++ Code) und obiger Macro ist dabei der einzige welcher eine "Funktionalität" besitzt und dient nur zum vereinfachten Nutzung des Loggers. Andere dienen allein als Compiler-Switch.
Dennoch konnte ich mein Problem vorerst lösen. Da ich die Module Schnittstellen implementieren lasse kann ich über diese jetzt Methoden zum Loggen bereitstellen, somit bleibt der Stream in seinem Tanzbereich

Btw: Wo bitte siehst Du im obigen Macro einen "Hack" da komm ich echt nicht drüber weg ...

Gut Schuß
VuuRWerK
-
Die doppelten Unterstriche sind eigentllich für den Compiler reserviert, evtl. macht das Trouble. Lass die einfach weg, du bist da eh in nem eigenen Scope in der Schleife, da gibt es keine Namenskollision.
Theoretisch könnte man das auch über templates machen. Da du aber für jede Kombination der Parameter eine eigene Templateinstanz bekommst, ist das in meinen Augen Speicherverschwendung. Das geht sehr gut mit nem Macro.Janjan hat scheinbar prinzipiell etwas gegen Macros, der mag auch BOOST_FOREACH nicht...
Also lass dich nicht ärgern.
BTW macht das log4cpp auch über Macros - und das wird immerhin von den Apacheleuten entwickelt - wie auch xerces.
-
Stimmt, mit den doppelten Unterstrichen ist noch eine blöde Angewohnheit, bei den Parameter etc. hab ich es ja auch schon weggelassen ^^
Wie gesagt konnt ich es jetzt über die Modul-Schnittstelle lösen was rein Design-technisch auch mehr Sinn macht damit jedes Modul einen einheitlichen Stream verwendet.
log4cpp war mir ein wenig zu wuchtig (kenne es aber auch von log4j aus Java) aber mich stört auch das es die Java-API nach implementiert hat nur damit es sich wirklich wie in Java "anfühlt".
Bei Janjan musst ich einfach nur schmunzeln, gab einen, in meinen Augen, völlig belanglosen Kommentar ab ohne jegliche Begründung etc. und reitet dabei nur auf Prinzipien rum, das belächle ich einfach mild

Ich hoffe das Boost.Log demnächst released wird
(@Janjan es nutzt Macros, ist also nix für Dich ;))Gut Schuß
VuuRWerK