Question

I have the following code which is redirecting my std::cout output to a log file.

std::ofstream out("out.txt");
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!

Now what I want is that whenever a newline is occurring, then the current time stamp will be written to the file.

I know I can achive this with:

std::cout << getTime() << "printing data" << std::endl;

But what I want is that of std::cout taking care of it automatically somehow. Is that possible?

Was it helpful?

Solution

I assume, that You want print the TimeStamp, if the first character of the next line appears in the output. Take a new class and inherit it from std::streambuf and connect it in the same way You do with the filebuf. If a newline-charater appears store this event in the object. Appears another character add the timestamp to the stream.

I wrote an example which use the RAII idiom for connecting the streambuf.

class AddTimeStamp : public std::streambuf
{
public:
    AddTimeStamp( std::basic_ios< char >& out )
        : out_( out )
        , sink_()
        , newline_( true )
    {
        sink_ = out_.rdbuf( this );
        assert( sink_ );
    }
    ~AddTimeStamp()
    {
        out_.rdbuf( sink_ );
    }
protected:
    int_type overflow( int_type m = traits_type::eof() )
    {
        if( traits_type::eq_int_type( m, traits_type::eof() ) )
            return sink_->pubsync() == -1 ? m: traits_type::not_eof(m);
        if( newline_ )
        {   // --   add timestamp here
            std::ostream str( sink_ );
            if( !(str << getTime()) ) // add perhaps a seperator " "
                return traits_type::eof(); // Error
        }
        newline_ = traits_type::to_char_type( m ) == '\n';
        return sink_->sputc( m );
    }
private:
    AddTimeStamp( const AddTimeStamp& );
    AddTimeStamp& operator=( const AddTimeStamp& ); // not copyable
    // --   Members
    std::basic_ios< char >& out_;
    std::streambuf* sink_;
    bool newline_;
};

call an object of this class in following way:

// some initialisation ..
{
    AddTimeStamp ats( cout ); // timestamp is active
    // every output to 'cout' will start with a 'getTime()' now
    // ...
} // restore the old streambuf in the destructor of AddTimeStamp

OTHER TIPS

That's a hack from a different point.

When you run the program, pipe the output into awk, and add there the time stamp. The command:

<program> | awk '{print strftime()" "$0}' > logfile

If you are using windows, you can download gawk from this website.

You can format the time printed by strftime. More data on that can be found in the manual

You want something like:

ostream & addTime() {
    std::cout << getTime();
    return std::cout;

and use it like this:

addTime() << "printing data" << std::endl;

try something like the following (it's just an abstract, I didn't test it):

class logger : ostream
{
    bool line = true;
public:
    template<typename T> ostream& operator<< (T somedata)
    {
        if (line)
            ostream << getTime();
        ostream << somedata;
        line = somedata == std::endl;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top