[Erledigt] Loggen mit stream?



  • Hallo,

    hier mal ein neues Problemchen. Ich würde gern einen Logger schreiben, der mit einer Syntax ähnlich Stringstreams arbeitet, also idealerweise so:

    Logger l;
    l << "Das ist ne Zahl: << 100 << "und wieder text ";
    // Bzw.
    l << "Das ist ne Zahl: << 100 << "und wieder text " << Logger::endl;
    

    Noch lieber wäre mir eigentlich sowas:

    l.log("Blah" << "blubb");
    

    Allerdings weiß ich nicht so recht, wie man das implentieren soll... habt ihr da Ideen?

    Dank & Gruß, Markus



  • Operator<< überladen. Dein zweiter Wunsch geht so direkt nicht.. Höchstens l.log(l << ...); was aber auch relativ Sinnbefreit ist. 😉



  • Schade, das hatte ich bereits befürchtet. Und mit was überlade ich den? Brauch ein da ein ostream Member oder wie würdest du das machen?



  • Kleines Beispielprogramm:

    #include <iostream>
    using namespace std;
    
    class Fubar
    {
    public:
      // Operator<< innerhalb der Klasse überladen
      Fubar& operator<<(int t)
      {
        cout << t;
        return *this;
      }
    };
    
    // Operator<< außerhalb der Klasse überladen
    Fubar& operator<<(Fubar &f, char c)
    {
      cout << c;
      return f;
    }
    
    int main()
    {
      Fubar f;
      f << 5 << 9 << 2;
      f << 'a' << 't' << 'c';
    }
    

    Sollte allerdings auch in deinem Buch stehen. 😉



  • Janjan schrieb:

    geht so direkt nicht.. Höchstens l.log(l << ...);

    Es müssten auch gehen:
    l.log() << "bla" << "blubb";
    oder
    l.log << "bla" << "blubb";



  • Mein Buch.. ähhhh... das hab ich ... verlegt... mein Hund hat's gefressen. 😉

    Danke dir, so hab ich's auch schon gemacht. Allerdings noch eine Kleinigkeit: Ich brauche einen endline-Operator, wie std::endl, damit die Zeile intern ins mit Datum und ein paar Infos Logfile geschrieben wird, kannst du mir sagen, wie ich da ein eigenes Logger::endl implementieren kann?


  • Mod

    TdZ schrieb:

    Noch lieber wäre mir eigentlich sowas:

    l.log("Blah" << "blubb");
    

    Diese Syntax kann man leicht mit Makros hinbekommen.



  • TdZ schrieb:

    Mein Buch.. ähhhh... das hab ich ... verlegt... mein Hund hat's gefressen. 😉

    Ein Buch sollte Grundvoraussetzung sein. 😉

    TdZ schrieb:

    Allerdings noch eine Kleinigkeit: Ich brauche einen endline-Operator, wie std::endl, damit die Zeile intern ins mit Datum und ein paar Infos Logfile geschrieben wird, kannst du mir sagen, wie ich da ein eigenes Logger::endl implementieren kann?

    Dies wird mittels Funktionszeiger gelöst. Du übergibst also dann die Funktion "endl" an den operator<<, welche als Parameter eine Referenz auf die Klasse annimmt und diese Referenz zurückgibt.

    Beispiel:

    #include <iostream>
    using namespace std;
    
    class Fubar
    {
    public:
      // Operator<< überladen, dass dieser Funktionszeiger annimmt
      Fubar& operator<<(Fubar& (*fp)(Fubar&))
      {
        (*fp)(*this);
        return *this;
      }
    };
    
    Fubar& myEndl(Fubar &f)
    {
      cout << "Mein eigenes Endl!";
      return f;
    }
    
    int main()
    {
      Fubar f;
      f << myEndl;
    }
    

    SeppJ schrieb:

    TdZ schrieb:

    Noch lieber wäre mir eigentlich sowas:

    l.log("Blah" << "blubb");
    

    Diese Syntax kann man leicht mit Makros hinbekommen.

    Und das wäre schrecklich. Makros sollten nicht für so einen Mist missbraucht werden. Dadurch wird der Code schwerer durchschaubar und es schleichen sich sehr leicht hinterhältige Fehler ein. Bitte bring ihm nicht so einen Müll bei.



  • So, hab's jetzt -- dank janjans Hilfe folgendermaßen gelöst:

    class Log
    {
    public:
        static Log& Warning(Log& l) {
            l.m_stream << std::endl;
            l.m_log+=getPrefix("Warning");
            l.m_log+=l.m_stream.str();
            l.m_stream.clear();
            return l;
        }
    
        static Log& Notice(Log& l) {
            l.m_stream << std::endl;
            l.m_log+=getPrefix("Notice");
            l.m_log+=l.m_stream.str();
            l.m_stream.clear();
            return l;
        }
    
        static Log& Error(Log& l) {
            l.m_stream << std::endl;
            l.m_log+=getPrefix("Error");
            l.m_log+=l.m_stream.str();
            l.m_stream.clear();
            return l;
        }
    
        Log()
        {
    
        }
    
        virtual ~Log()
        {
            m_stream.clear();
            m_log.clear();
        }
    
        Log& operator<<(char* p)
        {
            m_stream << p;
            return *this;
        }
        Log& operator<<(std::string s)
        {
            m_stream << s;
            return *this;
        }
        Log& operator<<(int n)
        {
            m_stream << n;
            return *this;
        }
        Log& operator<<(float n)
        {
            m_stream << n;
            return *this;
        }
    
        Log& operator<<(Log& (*fp)(Log&))
        {
            (*fp)(*this);
            return *this;
        }
    
        inline std::string getString()
        {
            return m_log;
        }
    
    protected:
    private:
        static std::string getPrefix(std::string desc="")
        {
            return std::string("00:00:00 [")+desc+std::string("]: ");
        }
    
        std::string m_log;
        std::stringstream m_stream;
    };
    

    Und funktionieren tut's so:

    Log l;
    l << "Blah der Text und ne NUmmer << 100 << 200.0f << Log::Notice;
    

    Vielen Dank nochmal für die Tips!


Anmelden zum Antworten