• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 544
  • Last Modified:

To IOStream gurus

Hi,
I am trying to implement logging system using iostreams. My question is: how can I add date/time stamp on iostream basis? What I want to acheive is as following:

cmylog << "Test" << std::endl;

And the output shall be

10:00 Test

(I will be able to configure time stamp format but it is beyond my question, do not worry about it)

Please advise

P.S. I will increase points for working solution.
0
proskig
Asked:
proskig
  • 5
  • 4
  • 4
1 Solution
 
mnashadkaCommented:
One way would be to store the data in a std::ostringstream, and when the stream insertion operator is called, you can see if the inserted data is the first data in the ostringstream (by checking ostringstream.str().empty()).  Then, when you see std::endl come in, dump the ostringstream.str() to the file and clear it.  This is the approach I took when I had a similar requirement.  Hope this helps.
0
 
proskigAuthor Commented:
mnashadka: What's the correct way to recognize std::endl? I mean flushing buffer? Another question is: which operator to overload ?
0
 
mnashadkaCommented:
Actually, probably an easier way would be to just have 2 stream insertion operators, like:
template<class T>
cmylog &operator<<(T &value)
{
  stream << value;
}

And then another one to dump the ostringstream to the file

cmylog &operator<<(std::ostream &(*end_of_line) (std::ostream &))
{
  file << time() << stream.str() << end_of_line;
  // Clear the ostringstream
}

Of course, the stream variable is the ostringstream and file is the ofstream.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
peterchen092700Commented:
I once did something similar, providing my own class with this (pseudo-)code:


class mystream
{
  ostream * os;
}

// default template to "redirect" all output to the ostream
template <class T>
mystream & operator << (mystream & s, T const & x)
{
  s->os << x;
}

// specific overload for endl:
mystream & operator << (mystream & s, std::endl const & x)
{
  s->os << x;
  s->os << ... // output time for new line
}

Peter


Note 1: I found the streams extremely slow for this purpose. Since we had to log *tons* of data, I finally rewrote the thing to use printf-style (which is less fun, but more readable and faster)

Note 2: I'm not quite sure about the const & - just tell me if there are problems.

0
 
mnashadkaCommented:
perterchen, what happens if you don't have a new line for a long time?  This is assuming that the next log statement will be coming within seconds.  Just curious.
0
 
proskigAuthor Commented:
I do have problems with specialization for std::endl

class mystream
{
  std::ostream *os;
};

// default template to "redirect" all output to the ostream
template <class T>
mystream & operator << (mystream & s, T const & x)
{
 *(s.os) << x;
}

// specific overload for endl:
mystream & operator << (mystream & s, std::endl & x)
{
 *(s.os) << x;
}


Produces error
error C2321: syntax error : unexpected 'endl'

for MSVC
0
 
peterchen092700Commented:
mnashadka: you're right - in this case, you need to use a flag

class mystream
{
 ostream * os;
 bool needWriteTime; // init to true in CTor
}

// default template to "redirect" all output to the ostream
template <class T>
mystream & operator << (mystream & s, T const & x)
{
 if (s->needWriteTime)
   s->os << "10:00 "; // ;)
 s->os << x;
}

// specific overload for endl:
mystream & operator << (mystream & s, std::endl const & x)
{
 s->os << x;
 s->needWriteTime = true;
}

proksig: I'll look into it, I'm myself not sure with the syntax...
0
 
mnashadkaCommented:
cmylog &cmylog::operator<<(std::ostream &(*end_of_line) (std::ostream &))
is the syntax for endl
0
 
mnashadkaCommented:
I still think it's better to buffer the output, though.  If you don't and your application is (or becomes) multithreaded, your log messages will be interspersed and you won't be able to tell them apart (I know this from experience).  But that's just my 2 cents.
0
 
peterchen092700Commented:
Hmmm... found a solution, but... seee below..

typedef ostream & (tEndl)(ostream & os);

mystream & operator << (mystream & s,  tEndl x)
{
   tEndl * endlfunc = endl;
   x(*s.os); // s.os << endl;
   if ( x == endlfunc)   // ***
      (*s.os) << "10:40 ";
   return s;
}


I initially thought the endl manip is declared as class - but no, its a function.

The point I find a bit awkward in an STL environment is that at ***, we actually have to compare two function pointers to see if the manipulator passed is actually "endl", or something else (like flush). Although I see no *technical* problem with this.

P.S. next comment: working sample (console app)
0
 
peterchen092700Commented:
#include "stdafx.h"
#include <ios>
#include <iostream>

using namespace std;

class mystream
{
   public:
      ostream * os;
      bool      needtime;
      mystream() { needtime = true; }
};

static int time; // instead of time....

// default template to "redirect" all output to the ostream
template <class T>
mystream & operator << (mystream & s, T const & x)
{
   if (s.needtime) {
      ++time;
      (*s.os) << time << " ";  
      s.needtime = false;
   }
 (*s.os) << x;
 return s;
}

int f(int);
int f(int,int);


// specific overload for endl:
//typedef std::basic_ostream<char,std::char_traits<char> >  & (tEndl)(std::basic_ostream<char, std::char_traits<char> > & os);
typedef ostream & (tEndl)(ostream & os);

mystream & operator << (mystream & s,  tEndl x)
{
   x(*s.os); // s.os << x;

   tEndl * endlfunc = endl/*<char, std::char_traits<char> >*/;
   if ( x == endl)
      s.needtime = true;


   return s;
}

int main(int argc, char* argv[])
{
   mystream s;
   s.os = &cout;

   s <<  "Hello World " << endl;
   s <<  "Yeah yeah yeah " << flush << "It works " << endl;    // flush: to test another manip
     return 0;
}

// it's not a clean example... but shows the principles
0
 
proskigAuthor Commented:
Cool Thanks!
0
 
proskigAuthor Commented:
Cool thanks.
0

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 5
  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now