Designfrage - Logging



  • Jo, damit könnte ich leben.

    Mit dem Provider habe ich noch ein Problem. Und daß man privat von seinem Template-Argument erbt. Sollte der Provider nicht nur einen ostream providen? st das Absicht, daß der logger kein globales Objekt ist? Das wäre für mich logisch.

    Bleibe ich mal bei dieser Aufrufsyntax, müßte da logger nicht ein namespace sein und die static Funktionen freie Funktionen sein? Die können sich ja dann trotzdem noch eines Meyers-Singletons bedienen. Aber wozu? Den logger einfach static in die log() tun, und schon wieder ein komplexes Muster abgeschossen. Gehört der Mutex nicht zum Provider? Ist gar der Provider das funktionslokale static Objekt? Und wird nicht nur der provider getypedeft? Ich würde da noch viel Schnipseln, kleinermachen, umräumen und so. Und dann einen Lecker Makro drum. 🤡
    Muß denn per typedef geschaltet werden? Der wird am Ende doch mit Umkommentierung umgeschaltet, dann kanns auch jede andere Weise sein, wo umkommentiert wird.

    ostream& getLogStream(){
       using std::clog;
    //   static ofstream clog("log.txt");//Ätsch, ich nehme doch eine Datei
       return clog;
    }
    

    Och nööö, jetzt fällt ja alles zusammen. Sorry.



  • Und was ist jetzt die "Message" aus deinem Post? Alles Kacke?



  • 314159265358979 schrieb:

    Und was ist jetzt die "Message" aus deinem Post? Alles Kacke?

    Nö. Am Ende mußte ich zwar lachen, aber bei den anderen Loggern muß ich immer weinen.

    Brauchst auch bei Fehler evtl nicht selber zu throwen. Vielleicht tut das da es auch
    http://www.cplusplus.com/reference/iostream/ios/exceptions/



  • volkard schrieb:

    Nö. Am Ende mußte ich zwar lachen, aber bei den anderen Loggern muß ich immer weinen.

    Darf ich das so verstehen, dass mein Logger zwar brauchbar und verbesserbar, aber überdurchschnittlich "schön" ist?

    volkard schrieb:

    Brauchst auch bei Fehler evtl nicht selber zu throwen. Vielleicht tut das da es auch
    http://www.cplusplus.com/reference/iostream/ios/exceptions/

    Ich werfe lieber eigene Exceptions, da ich so im Fehlerfall feststellen kann, dass der Fehler zumindest bedacht wurde. Wenn dann eine andere Exception geworfen wird, bemerke ich einen unbekannten Fehler und kann die Behandlung einbauen.



  • Das kam bei meiner ersten Schrumpfkur raus.

    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <boost/date_time/posix_time/posix_time.hpp>
    #include <boost/thread.hpp>
    
    template <typename Head>
    void write_to_stream(std::ostream& os, Head&& head)
    {
    	os << head;
    }
    
    template <typename Head, typename... Tail>
    void write_to_stream(std::ostream& os, Head&& head, Tail&&... tail)
    {
    	os << head;
    	write_to_stream(os, std::forward<Tail>(tail)...);
    }
    
    namespace logger
    {
    
    std::ostream& getLogStream()//in die logger.cpp
    {
    	using namespace std;
        static std::ofstream clog("log.txt");//Ätsch, ich nehme doch eine Datei
    	return clog;
    }
    
    boost::mutex mtx;
    
    template <typename... Args>
    void log(Args&&... args)
    {
    //auskommentiert, weil boost gerade nicht geht
    //	const auto local_time = boost::posix_time::microsec_clock::local_time();
    //	const std::string time_string = boost::posix_time::to_simple_string(local_time);
    
        std::ostream& log=getLogStream();
    	{
    		const boost::mutex::scoped_lock lock(mtx);
    		write_to_stream(log,'[' , "time_string" , "] ", std::forward<Args>(args)...);
    	}
    }
    
    template <typename... Args>
    void server (Args&&... args)
    {
    	log("<Server>  :: ", std::forward<Args>(args)...);
    }
    
    template <typename... Args>
    void client (Args&&... args)
    {
    	log("<Client>  :: ", std::forward<Args>(args)...);
    }
    
    template <typename... Args>
    void error  (Args&&... args)
    {
    	log("<Error>   :: ", std::forward<Args>(args)...);
    }
    
    template <typename... Args>
    void warning(Args&&... args)
    {
    	log("<Warning> :: ", std::forward<Args>(args)...);
    }
    
    template <typename... Args>
    void info   (Args&&... args)
    {
    	log("<Info>    :: ", std::forward<Args>(args)...);
    }
    
    }//namespace logger
    
    int main()
    {
        logger::client("hallo ","welt!");
    }
    


  • Sieht gut aus 🙂

    Allerdings...
    - Ich kann meine eigenen Exceptions nicht werfen. Das wäre mir doch ganz wichtig 😉
    - Vielleicht sollte man den mutex static machen



  • 314159265358979 schrieb:

    - Vielleicht sollte man den mutex static machen

    Oder in die logger.cpp stopfen.

    314159265358979 schrieb:

    - Ich kann meine eigenen Exceptions nicht werfen. Das wäre mir doch ganz wichtig 😉

    Mhmm. Ist das Aufgabe des Loggers oder brauchst Du einen Wrapper um Files, weil Du bei Files immer Deine eigenen Exceptions werfen willst?
    Oder mach irgendwas Kompliziertes.



  • volkard schrieb:

    Oder in die logger.cpp stopfen.

    Geht das denn so ohne weiteres? Woher weiß der Header, dass der in der .cpp gemeint ist? Eine extern-Deklaration würde den Mutex dann auch für alle, die den Header includen bekannt machen, oder nicht?

    volkard schrieb:

    Mhmm. Ist das Aufgabe des Loggers oder brauchst Du einen Wrapper um Files, weil Du bei Files immer Deine eigenen Exceptions werfen willst?
    Oder mach irgendwas Kompliziertes.

    Ich möchte das eigentlich immer bei Files machen, auch bei Sockets mache ich das. Was schlägst du vor?



  • So, ich habe den Logger nun nochmal überarbeitet. Ich habe mich an deinem orientiert, ihn allerdings ein wenig anders gebaut. Hier einmal der Code...

    namespace logger
    		{
    			namespace detail
    			{
    				std::ostream& logger_stream();
    				boost::mutex& logger_mutex();
    
    				template <typename... Args>
    				void log(Args&&... args)
    				{
    					const auto local_time = boost::posix_time::microsec_clock::local_time();
    					const std::string time_string = boost::posix_time::to_simple_string(local_time);
    
    					{
    						const boost::mutex::scoped_lock lock(logger_mutex());
    						write_to_stream(logger_stream(), '[', time_string, "] ", std::forward<Args>(args)...);
    					}
    				}
    			}
    
    			template <typename... Args>
    			void server (Args&&... args) { detail::log("<Server>  :: ", std::forward<Args>(args)...); }
    
    			template <typename... Args>
    			void client (Args&&... args) { detail::log("<Client>  :: ", std::forward<Args>(args)...); }
    
    			template <typename... Args>
    			void error  (Args&&... args) { detail::log("<Error>   :: ", std::forward<Args>(args)...); }
    
    			template <typename... Args>
    			void warning(Args&&... args) { detail::log("<Warning> :: ", std::forward<Args>(args)...); }
    
    			template <typename... Args>
    			void info   (Args&&... args) { detail::log("<Info>    :: ", std::forward<Args>(args)...); }
    		}
    

    .cpp

    namespace logger
    		{
    			namespace detail
    			{
    				std::ostream& logger_stream()
    				{
    					static std::ofstream logger("bot.log");
    					static bool dummy = [&logger]() { logger.exceptions(std::ofstream::badbit | std::ofstream::failbit); return true; }();
    					(void)dummy;
    					return logger;
    				}
    
    				boost::mutex& logger_mutex()
    				{
    					static boost::mutex mtx;
    					return mtx;
    				}
    			}
    		}
    

    Was mir nicht gefällt, ist der weg, wie ich hier Exceptions aktiviere. Ich würde ja eine Funktion create_logger_stream() machen, die das erledigt, aber leider lassen sich Streams nicht mal moven 😞



  • Hihi, da hab ich die Lösung doch glatt gefunden, direkt nachdem ich gepostet habe. Sieht nun so aus...

    std::ostream& create_logger_stream()
    				{
    					static std::ofstream logger("bot.log");
    					logger.exceptions(std::ofstream::badbit | std::ofstream::failbit);
    					return logger;
    				}
    
    				std::ostream& logger_stream()
    				{
    					static std::ostream& logger = create_logger_stream();
    					return logger;
    				}
    

Anmelden zum Antworten