Eigene Log-Klasse erstellen, mit Stringstream



  • Hallo Leute,

    ich bin gerade Dabei mir eine Log-Klasse zu erstellen, dazu hätte ich ein paar Fragen ...

    Hier erstmal das, was ich schon hab:

    log.h

    #ifndef _log_h_
    #define _log_h_
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    
    class CLog {
        public:
            std::stringstream &data;
            std::ostream &os;
    
            #ifdef NDEBUG
                std::ofstream &of;
                std::string file;
            #endif
    
        public:
            CLog();
            #ifndef NDEBUG
                CLog(std::stringstream &data, std::ostream &os = std::cout);
            #else
                CLog(std::string &file = "log.log");
                CLog(std::stringstream &data, std::string &file = "log.log");
            #endif
            CLog(const CLog &log);
            virtual ~CLog();
    
        public:
            CLog operator=(const CLog &log);
            void operator<<(const CLog &log);
            #ifndef NDEBUG
                friend std::ostream& operator<<(std::ostream &os, CLog &log);
            #else
                friend void operator<<(std::ofstream &of, CLog &log);
            #endif
            template<typename LOG> void operator<<(LOG log);
            friend CLog operator<<(CLog log, int buff);
            friend CLog operator<<(CLog log, std::string buff);
    };
    
    #endif //_log_h_
    

    log.cpp

    #include "log.h"
    
    using namespace std;
    
    //Konstruktoren
        #ifndef NDEBUG
            CLog::CLog() : os(cout), data(){
            }
    
        #else
            CLog::CLog() : os(cout), data(), of(){
                #ifdef NDEBUG
                    this->file = "log.log";
                    ofstream of;
                    of.open(this->file.c_str());
                    of.close();
                #endif
            }
        #endif
    
        #ifndef NDEBUG
            CLog::CLog(stringstream &data, ostream &os) : data(data), os(os){
            }
        #else
            CLog::CLog(string &file) : of(), data(), os(cout), file(file){
                ofstream of;
                of.open(this->file.c_str());
                of.close();
            }
    
            CLog::CLog(stringstream &data, string &file) : of(), data(data), os(cout), file(file){
                ofstream of;
                of.open(this->file.c_str());
                of.close();
            }
        #endif
    
        #ifndef NDEBUG
            CLog::CLog(const CLog &log) : os(cout), data(){
                stringstream ss;
                ss.str("");
                ss.clear();
                ss<<log.data.str();
            }
        #else
            CLog::CLog(const CLog &log) : os(cout), data(), of(){
                this->data.str("");
                this->data.clear();
                this->data<<log.data;
            }
        #endif
    
    //Destruktor
        CLog::~CLog(){
        }
    
    //Operatoren
        CLog CLog::operator=(const CLog &log){
            this->data.str("");
            this->data.clear();
            this->data<<log.data;
            return *this;
        }
    
        void CLog::operator<<(const CLog &log){
            this->data.str("");
            this->data.clear();
            this->data<<log.data;
            #ifndef NDEBUG
                this->os<<*this;
            #else
                this->of<<*this;
            #endif
        }
    
        #ifndef NDEBUG
            ostream& operator<<(std::ostream &os, CLog &log){
                return os<<log.data.str().c_str();
            }
        #else
            void operator<<(std::ofstream &of, CLog &log){
                of.open((log.file.str()).c_str(), ios::out|ios::app);
                if(of.good()){
                    of<<log.data.c_str();
                    of.close();
                }
                else cout<<log.data.str();
            }
        #endif
    
        template<typename LOG> void CLog::operator<<(LOG log){
            this->data<<log;
            #ifndef NDEBUG
                this->os<<*this;
            #else
                this->of<<*this;
            #endif
            this->data.str("");
            this->data.clear();
        }
    
        CLog operator<<(CLog log, int buff){
            log.data<<buff;
            #ifndef NDEBUG
                log.os<<log.data;
            #else
                log.of<<log.data;
            #endif
            log.data.str("");
            log.data.clear();
        }
    
        CLog operator<<(CLog log, string buff){
            log.data<<buff;
            #ifndef NDEBUG
                log.os<<log.data;
            #else
                log.of<<log.data;
            #endif
            log.data.str("");
            log.data.clear();
        }
    

    Hier gleich mal mehrere Fragen:
    1. Ist das so in Ordnung mit dem

    #ifndef NDEBUG
    

    oder sollte ich es lieber anders machen?
    2. Sollte ich statt Stringstream etwas anderes nehmen?
    3. Wenn ich Daten in den Stringstream schreiben will (log.cpp Zeile 43, 49...), Beendet immer mein Programm, ohne Fehler oder Sonstiges
    4. Kann ich dann einfach in anderen Klassen einen friend Operator für die Log-Klasse deklarieren?

    class foo {
    foo();
    ...
    friend CLog& operator<<(CLog &log, foo &foo_obj);
    ...
    };
    

    Für Anregungen stehe ich gerne zur Verfügung

    Gruß
    Simon



  • varginator schrieb:

    Hier gleich mal mehrere Fragen:
    1. Ist das so in Ordnung mit dem

    #ifndef NDEBUG
    

    oder sollte ich es lieber anders machen?

    Im Prinzip ja - aber siehe 2.)

    varginator schrieb:

    2. Sollte ich statt Stringstream etwas anderes nehmen?

    Ja - die Erfinder von den C++-Streams haben dafür das Umschalten eines ostreams vorgesehen. Siehe auch den Parallel-Thread.

    varginator schrieb:

    3. Wenn ich Daten in den Stringstream schreiben will (log.cpp Zeile 43, 49...), Beendet immer mein Programm, ohne Fehler oder Sonstiges

    Der member 'data' ist eine Referenz und wird nicht initialisiert; und führt damit zu undefiniertem Verhalten. - bei mir übersetzt das gar nicht!?

    varginator schrieb:

    4. Kann ich dann einfach in anderen Klassen einen friend Operator für die Log-Klasse deklarieren?

    class foo {
    foo();
    ...
    friend CLog& operator<<(CLog &log, foo &foo_obj);
    ...
    };
    

    Ja - aber besser Du deklarierst einen friend-Ausgabe-Operator mit std::ostream& - dafür ist er da. In beiden Fällen sollte es 'const foo& foo_obj' heißen.

    Gruß
    Werner



  • Hallo Werner,

    danke für deine Hilfe, ich hab nur noch ein paar Fragen, wie ich das dann realisieren kann:

    zu 1. Ich versteh nich ganz was du damit meinst, wenn ich im Debug-Mode auf cout ausgeben will und im Release auf ostream, dann brauch ich doch defines, oder?

    zu 2. Wie würde man das am besten in ner Klasse realisieren?
    Kann ich einfach ne streambuf-Variable reinhängen?

    class CLog {
        CLog();
    
        std::streambuf* old_stream;
    
        //was muss ich dann beim <<-Operator hinschreiben falls ichs mit dem machen will?
    };
    
    //nochmal mit defines
    CLog::CLog(){
        #ifndef NDEBUG
            old_stream = clog.rdbuf(cout.rdbuf());
        #else
            std::ofstream logfile("log.txt");
            old_stream = clog.rdbuf(logfile.rdbuf());
        #endif
    }
    
    int main ( int arg, char* argv[] )
    {
        CLog log; // nirgendwo hin
    
        clog << "hello world" << endl;  //oder iwie ne Klassenvariable?
    
        clog.rdbuf( log.old_stream );
        return 0;
    }
    

    zu 3. Aso, ok, aber ohne Referenz hat ers bei mir nich genommen 🙂

    zu 4. Ja, das kann ich schon machen, aber ich will ja im Release den Output in ne Datei
    soll ich da dann defines setzen?

    Ich will ja den gleichen Aufruf im Debug und im Release, dh. ich gebe

    log<<"Text"<<endl;
    

    ein, dann soll er im Debug in die Konsole schreiben und im Release in ne Datei

    Gruß
    Simon



  • Hallo Leute,

    ich hab jetzt die Lösung für mein Problem gefunden:

    log.h

    #ifndef _log_h_
    #define _log_h_
    
    #include <fstream>
    #include <iostream>
    #include <streambuf>
    #include <string>
    
    class CLog {
        public:
            CLog();
            CLog(std::string file);
            ~CLog();
    
        protected:
            std::streambuf* old_stream;
            #ifdef NDEBUG
                std::ofstream of;
            #endif
    };
    
    #endif //_log_h_
    

    log.cpp

    #include "log.h"
    
    using namespace std;
    
    CLog::CLog(){
        #ifndef NDEBUG
            old_stream = clog.rdbuf();
            clog.rdbuf(cout.rdbuf());
        #else
            of.open("log.txt");
            old_stream = clog.rdbuf();
            clog.rdbuf(of.rdbuf());
        #endif
    }
    
    CLog::CLog(string file){
        #ifndef NDEBUG
            old_stream = clog.rdbuf();
            clog.rdbuf(cout.rdbuf());
        #else
            of.open(file.c_str());
            old_stream = clog.rdbuf();
            clog.rdbuf(of.rdbuf());
        #endif
    }
    
    CLog::~CLog(){
        clog.rdbuf(old_stream);
        #ifdef NDEBUG
            of.close();
        #endif
    }
    

    main.cpp

    #include "log.h"
    
    int main(){
        CLog log();
        clog<<"Hallo Welt"<<endl;
        cin.get();
        return 0;
    }
    

    | EDIT | noch nen Konstruktor hinzugefügt, um die Datei anzugeben

    Gruß Simon


Anmelden zum Antworten