Logfile



  • Hi,
    ich möchte von meinem Programm eine Logfile anlegen lassen. Wie stellt man das am elegantesten und funktionellsten an?
    Ich denke einfach ein ofstream anlegen und Zeichen hineinzuschieben ist nicht so das Wahre oder?

    Gartenzwerg



  • Ich würde es so machen:

    Man nehme std::vectorstd::string und speichere darin alles was geloggt werden soll. Beim Beenden des Programms kannst du dann, via ofstream, den Inhalt des vectors einfach in eine Datei schreiben.



  • Dann verlierst du evtl. deine Logdaten wenn das Programm nicht normal beendet wird oder der Computer abstürzt.





  • Braunstein schrieb:

    Dann verlierst du evtl. deine Logdaten wenn das Programm nicht normal beendet wird oder der Computer abstürzt.

    Stimmt, hab ich gar nicht drüber nachgedacht!



  • Gartenzwerg schrieb:

    Hi,
    ich möchte von meinem Programm eine Logfile anlegen lassen. Wie stellt man das am elegantesten und funktionellsten an?
    Ich denke einfach ein ofstream anlegen und Zeichen hineinzuschieben ist nicht so das Wahre oder?

    Am besten ist, einen extra Thread dafuer zu starten, und dann die Log-Nachrichten in eine Queue zu schreiben. Der Thread liest die Queue blockweise aus (also alle Nachrichten in der Queue auf einmal), oeffnet die Logdatei, haengt die Eintraege ans Ende der Datei, schliesst die Datei wieder und wartet auf neue Nachrichten in der Queue.

    Die Log-Durchsatzrate, die damit erzielt werden kann, betraegt, falls erforderlich, locker 100-150 MB / sec. oder mehr (je nach I/O Rate des Systems).

    Gut ist auch die Verwendung asynchroner I/O, um die Log-Output-Rate zu maximieren.



  • Gartenzwerg schrieb:

    Hi,
    ich möchte von meinem Programm eine Logfile anlegen lassen. Wie stellt man das am elegantesten und funktionellsten an?
    Ich denke einfach ein ofstream anlegen und Zeichen hineinzuschieben ist nicht so das Wahre oder?

    doch.

    ofstream(LOGFILE,ios::append)<<line<<'\n';
    

    du hast grundsätzlich das problem, daß du das file nach jeder zeile fluschen musst, weil im falle einer schutzverletzung sonst nicht die einzig interessante zeile, also die genau vor dem fehler in der datei landet.

    falls performance beim logging ein problem sein sollte, gehen wir andere wege. vielleicht die threads von Power Off (muss bei multithreading wohl eh sein). ich würde pipes vorziehen und einen zweiten prozess, der die logdatei schreibt. das garantiert, daß ein erfolgreiches write in die pipe auch auf die platte geschrieben werden kann, egal welchen abkacker das eigene programm macht.



  • danke,
    ich glaube, ich ziehe dann doch die ofstream-variante vor.

    Gartenzwerg



  • Naja, ich würde es schon in eine Funktion kapseln:

    void write_to_log(const std::string& s)
    {
        static std::ofstream o;
        o.open("logfile.log",ios::out|ios::app);
        o<<str;
        o.close()
    };
    


  • ness schrieb:

    Naja, ich würde es schon in eine Funktion kapseln:

    void write_to_log(const std::string& s)
    {
        static std::ofstream o;
        o.open("logfile.log",ios::out|ios::app);
        o<<str;
        o.close()
    };
    

    ruf niemals close auf, wenn es der destuktor auch macht.
    rof niemals open auf, wenn es der konstruktor auch macht.

    und jetzt zeig mir mal die funktion, wie sie benutzt wird. ich hab

    long ip_adresse;
    string requuse_uri;
    ...
    ofstream("log.txt")<<"request "<<request_uri<<" from "<<ip_adresse<<'\n';
    

    mach mal einen vorschlag, wie das mit ner funktion geht. und wenn möglich, schreib nicht für jeden aufruf eine eigene funktuin.



  • Das war natürlich nur ein Vorschlag...
    Aber die Argumente verstehe ich nicht:

    volkard schrieb:

    ruf niemals close auf, wenn es der destuktor auch macht.
    rof niemals open auf, wenn es der konstruktor auch macht.

    Aber destruktor wird nur einmal aufgerufen, ich will die Datei aber nach jedem Eintrag schließen.
    Aber das Objekt wird nur einmal initialisiert, ich will es aber mehrmals öffnen...

    volkard schrieb:

    long ip_adresse;
    string requuse_uri;
    ...
    ofstream("log.txt")<<"request "<<request_uri<<" from "<<ip_adresse<<'\n';
    

    Klar, das geht nicht. Eigentlich wollte ich mir nur die Tipperei des .open(...);...;.clos(...); ersparen. Ich hab das ganze mit einem Makro gemacht, als ich auf das Problem gestoßen bin:

    #define write_to_log(x)\
    logfile.open(LOGFILENAME,ios::out|ios::app);\    //LOGFILENAME mit define eingeführt, logfile global
    logfile<<x;\
    logfile.close()
    

    Nun gibt es ein Problem mit der initialisierung von logfile, also ist das Makro ungeeignet für ausgaben vor main().
    Außerdem ist es ein Makro, und da die (aus gutem Grund) nicht beliebt sind und man vor allem dieses ersetzen kann: (mal eben hingeschreieben)

    class logstream
    {
    private:
        std::string logfile;
        std::fstream lstr;
    public:
        logstream(const std::string& lfn):logfile(lfn){};
        template<class T>
        void inner_op_out(typename boost::call_traits<T>::param_type t)    //damit sollte man int& (und die nicht vorhandenen Überladungen dafür) umgehen können
        {
            lstr.open(logfile,ios::app|ios::out);
            lstr<<T;
            lstr.close();    //suboptimal, aber mir fällt nichts anderes ein...
        };
    };
    
    template<class T>
    logstream& operator<<(logstream& l,typename boost::call_traits<T>::param_type t)
    {
        l.inner_op_out(t);
        return l;
    };
    

    Jetzt haben wir immer noch eine globale Variable, aber kein Makro mehr. Entweder wir lassens so, oder benutzen ein singleton...


Anmelden zum Antworten