9

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?

Felix Glas
  • 15,065
  • 7
  • 53
  • 82
Sigcont
  • 717
  • 2
  • 8
  • 16
  • You should consider to provide your own `std::streambuf` for e.g. a `std::ostream` compliant logger class implementation to achieve this. – πάντα ῥεῖ Mar 01 '14 at 18:49
  • 2
    Without implementing an open-ended streambuf that accumulates output and slips a timestamp in first on every flush, I'm cautiously hesitant to say this is possible another way. The iostream guys are known to pull rabbits out of the oddest places, so never say never, but knowing what I know of them, I don't see it likely another way. – WhozCraig Mar 01 '14 at 18:56
  • Considering the fact that you are new to c++, and the answers given rely on quite advanced manipulation of the IO process, I will recommend you either use Paul Evans answer, or give it up. – elyashiv Mar 01 '14 at 19:21

4 Answers4

16

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
cpp-progger
  • 406
  • 3
  • 6
3

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

elyashiv
  • 3,623
  • 2
  • 29
  • 52
0

You want something like:

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

and use it like this:

addTime() << "printing data" << std::endl;
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • 1
    He wants `std::cout << something-here` to prepend a timestamp transparently. I.e. everywhere `std::cout` is used not only gets redirected to the target output file, but gets timestamp preambles on every line written without ever changing the *caller* side. – WhozCraig Mar 01 '14 at 18:53
  • 1
    @Evans, I don't want like that. I will use std::cout<<"printing data"< – Sigcont Mar 01 '14 at 18:53
  • If you're already there to provide an extra function, you should make it a general `std::ostream` manipulator! – πάντα ῥεῖ Mar 01 '14 at 19:02
  • @πάνταῥεῖ so you'd write `std::cout << getTime ...` because he didn't want `std::cout << getTime() ...`? – Paul Evans Mar 01 '14 at 19:22
  • S.th. like this yes (as for `std::hex` or similar)! Though this solution doesn't match the OP's question, it would be definitely better style! At least you could declare it as a parameterized manipulator class for e.g. specifying timestamp format options. – πάντα ῥεῖ Mar 01 '14 at 19:24
0

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;
    }
}
elyashiv
  • 3,623
  • 2
  • 29
  • 52