I'm adding functions to my (simple) log class to make it usable like a stream.
Currently, after some modifications, I got this (in my cpp):
// blah blah blah...
// note: here String is a defined as: typedef std::string String;
void Log::logMessage( const String& message )
{
logText(); // to be sure we flush the current text if any (when "composing" a message)
addText( message );
logText(); // really log the message and make the current text empty
}
// blah blah blah...
Log& operator<<( Log& log, const std::stringstream& message )
{
log.logMessage( message.str() );
return log;
}
Log& operator<<( Log& log, const String& message )
{
log.addText( message );
return log;
}
Now in my "client" app I'm using this code to check the result (m_log is a valid pointer as you have already guessed):
gcore::Log& log = *m_log;
log << getName() << " : application created.";
log << "This is a test for " << getName();
Now the problem I got is that logText() (and logMessage) is never called because this test code will only call the << operator with String.
What I need is a way to call logText() when the given steam of string is finished :
log << getName() << " : application created.";
would be equivalent to
log.addText( getName() );
log.addText( " : application create." );
log.logText();
I'm not sure how to do this or even if it's possible. My first guess is that it would be possible to use std::endl at the end of the stream like this :
log << getName() << " : application created." << std::endl;
Or something equivalent, but if it's possible to do it without adding objects to the stream, that would be nice.
Any idea?
You can create a temp object and use his destructor to catch the end of the statement:
following code should give you the basic idea
class Log
{
public:
class Sublog
{
public:
Sublog(const std::string& message)
{
std::cout << message;
}
void addText(const std::string& message)
{
std::cout << message;
}
~Sublog()
{
std::cout << std::endl;
}
Sublog& operator<<(const std::string& message )
{
this->addText(message);
return *this;
}
};
};
Log::Sublog operator<<( Log& log, const std::string& message )
{
return Log::Sublog(message);
}
which would be used like this
int main()
{
Log log;
log << "Foo" << "bar";
log << "baz" << "plop";
}
after each semicolon, the destructor of Sublog is called
Klaim: the (working and effective) implementation of this solution in my case :
in the Log header :
/** To allow streaming semantic on logs (used in << operator) .
*/
class LogStreamer
{
public:
LogStreamer( Log& log, const String& text )
: m_log( log )
{
m_log.addText( text );
}
~LogStreamer()
{
m_log.logText();
}
LogStreamer& operator<<( const String& text )
{
m_log.addText( text );
return *this;
}
private:
Log& m_log;
};
GCORE_API LogStreamer operator<<( Log& log, const String& message );
and in the cpp file:
LogStreamer operator<<( Log& log, const String& message )
{
return LogStreamer( log, message );
}
Related
I have a macro that does exactly what I want it to do:
#define LOG(x)\
do { if (!cpp::app::g_app) {\
ASSERT("CANNOT LOG IF THERE IS NO CPP APP OBJECT" == 0);\
}\
else \
{ \
std::stringstream s; s << cpp::timing::currentDateTime(); s << '\t'; s << x << std::endl; \
*cpp::app::g_app << s.str(); \
cpp::app::g_app->flush(true);\
} \
} while(0)
#endif
Its really nice, because I can:
LOG("On first log line " << 0 << "Still on first log line")
..and a newline is inserted once the LOG macro is done.
Output looks like:
<date / time> On First log line 0 Still on first log line
... subsequent lines here
My question is how to overload << operator on my logging class to do the same?
If I simply overload << operator and return *this (where my logging case can be converted to ostream) then if I do:
mylogger << "First line " << "Still on first line";
then the output is something like:
<date and time> First line
<date and time> Still on first line.
So, I want to emulate the macro behaviour with the << operator. I want a newline automatically when the whole chain of << operations is complete, just like in the macro. But, since macros are evil, I'd rather convert it to a proper function.
Is this achievable?
Edit: Matt's idea about a helper class is quite nice. Based on his suggestion, I made the following disposable helper class:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
log& operator << (const T& t)
{
m_ss << t;
return *this;
}
virtual ~log(){
m_stream << cpp::timing::currentDateTime() << "\t" << m_ss.str() << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
std::stringstream m_ss;
};
Use it like:
log() << "All this text" << " will be on one line in the logfile, with date and time prepended ";
log() << "And this lot falls on line 2, with date and time prepended";
I hope that helps Galik and others who may be wanting the same thing.
A small improvement to the solution offered in the question, that creates fewer temporary objects:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
std::ostream& operator<< (const T& t)
{
return m_stream << cpp::timing::currentDateTime() << "\t" << t;
}
virtual ~log(){
m_stream << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
};
The temporary instance of log() will be destroyed at the end of the full-expression even if it isn't returned from operator<<. Might as well get rid of the middle-man and the extra stringstream buffer (which btw, doesn't respect the existing formatting options on the main stream -- this could be good or bad)
I have some code that you may find useful.
Its not heavily tested. I am hoping to expand on this to supply a producer/consumer queue which is why I am not using it at the moment. I am still using a macro like you :)
#include <sstream>
#include <memory>
#include <fstream>
#include <iostream>
#include <ctime>
namespace log {
typedef std::stringstream sss; // <3 brevity
class writer
{
private:
std::ostream& sink;
std::string endl = "\n";
std::string get_stamp()
{
time_t rawtime = std::time(0);
tm* timeinfo = std::localtime(&rawtime);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
public:
writer(std::ostream& sink): sink(sink) {}
void add_line(sss* ss)
{
sink << get_stamp() << " " << ss->rdbuf() << endl;
}
};
// this is used to build the log string in an sts::ostringstream
// which gets std::moved to each new temporary buffer when <<
// is invoked
struct buffer
{
writer& lw;
sss* ss;
buffer(writer& lw): lw(lw), ss(new sss) {}
buffer(const buffer& buf) = delete;
buffer(buffer&& buf): lw(buf.lw), ss(buf.ss) { buf.ss = nullptr; }
~buffer() { if(ss) lw.add_line(ss); delete ss; }
};
// each << creates a new temporary buffer that std::moves
// the std::ostringstream on to the next
template<typename Type>
buffer operator<<(buffer&& buf, const Type& t)
{
(*buf.ss) << t;
return std::move(buf);
}
// A write to a writer creates a temporary buffer and passes
// the << on to that
template<typename Type>
buffer operator<<(writer& lw, const Type& t)
{
return std::move(buffer(lw) << t);
}
} // log
int main()
{
std::ofstream ofs("output.log");
log::writer fout(ofs); // write to file
log::writer lout(std::cout); // write to std output
lout << "A " << 0.7 << " B";
fout << "wibble: " << 2;
}
The way this works is that writing to a log::writer via << causes a temporary log::buffer to be created. Subsequent writes << to the log::buffer create new temporary log::buffer objects which std::move an internal std::ostringstream between them. Because only the final log::buffer object has a non-null std::ostringstream* (because it was std::moved down when it collapsed) it writes the entire line to the log::writer.
My rather simple take on the situation:
class logger{
private:
unsigned int support_count;
std::ostream& output_stream;
public:
logger(std::ostream& str)
:support_count(0),
output_stream(str)
{}
class support_buffer{
private:
logger& l;
support_buffer(logger& l)
:l(l)
{
l.support_count++;
}
public:
support_buffer(const support_buffer& buf)
:l(buf.l)
{
l.support_count++;
}
~support_buffer(){
l.support_count--;
if (l.support_count==0){
l.output_stream << std::endl;
}
}
template <typename T>
support_buffer& operator<<(const T& t){
l.output_stream << t;
return *this;
}
friend class logger;
};
template <typename T>
support_buffer operator<<(const T& t){
output_stream << "<date/time> " << t;
return support_buffer(*this);
}
friend class support_buffer;
};
int main()
{
logger l(std::cout);
l << "Line 1: " << 0 << "Still on line 1";
l << "Line 2";
return 0;
}
Just create a wrapper class that passes all printed elements to our logger and on destruction of the last one send a new line. If you are sure that your output buffer is only being used by your logger class you could even resign of counting support objects. Just print new line character before a line instead of after it.
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?
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
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;
}
}
In our project we use the c++ stream operator (<<) in our object model to print out an easy readible format of the data. A simplified example is this:
std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
oStream << "[SomeMember1: " << iOwnClass._ownMember1 << "]\n";
oStream << "[SomeMember2: " << iOwnClass._ownMember2 << "]\n";
}
Resulting in this in the logging:
[SomeMember1: foo]
[SomeMember2: bar]
What we want now is to be able to indent the result of that operator. Some calling class might not want the result like this, but want to add 2 spaces indention before each line. We could add a member to our class specifying the indention, but that does not seem to be an elegant solution.
Of course this is not a very big issue, but our logging would be so much nicer if this would work.
Thanks
The simplest solution is to slip a filtering streambuf between the
ostream and the actual streambuf. Something like:
class IndentingOStreambuf : public std::streambuf
{
std::streambuf* myDest;
bool myIsAtStartOfLine;
std::string myIndent;
std::ostream* myOwner;
protected:
virtual int overflow( int ch )
{
if ( myIsAtStartOfLine && ch != '\n' ) {
myDest->sputn( myIndent.data(), myIndent.size() );
}
myIsAtStartOfLine = ch == '\n';
return myDest->sputc( ch );
}
public:
explicit IndentingOStreambuf(
std::streambuf* dest, int indent = 4 )
: myDest( dest )
, myIsAtStartOfLine( true )
, myIndent( indent, ' ' )
, myOwner( NULL )
{
}
explicit IndentingOStreambuf(
std::ostream& dest, int indent = 4 )
: myDest( dest.rdbuf() )
, myIsAtStartOfLine( true )
, myIndent( indent, ' ' )
, myOwner( &dest )
{
myOwner->rdbuf( this );
}
virtual ~IndentingOStreambuf()
{
if ( myOwner != NULL ) {
myOwner->rdbuf( myDest );
}
}
};
To insert, just create an instance of the streambuf:
IndentingOStreambuf indent( std::cout );
// Indented output...
When indent goes out of scope, everything returns to normal.
(For logging, I have one that is a bit more complex: the
LoggingOStreambuf takes __FILE__ and __LINE__ as arguments, sets
myIndent to a formatted string with these arguments, plus a time
stamp, resets it to an indentation string after each output, collects
all of the output in an std::ostringstream, and outputs it atomically
to myDest in the destructor.)
This can be done using a custom stream-manipulator that stores the desired indentation-level in a word of the internal extensible array of the stream. You can request such a word using the function ios_base::xalloc. This function will give you the index of your word. You can access it using ios_base::iword. One way to implement that would be this:
struct indent {
indent(int level) : level(level) {}
private:
friend std::ostream& operator<<(std::ostream& stream, const indent& val);
int level;
};
std::ostream& operator<<(std::ostream& stream, const indent& val) {
for(int i = 0; i < val.level; i++) {
stream << " ";
}
return stream;
}
std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
oStream << indent(oStream.iword(index)) << "[SomeMember1: " <<
iOwnClass._ownMember1 << "]\n";
oStream << indent(oStream.iword(index)) << "[SomeMember2: " <<
iOwnClass._ownMember2 << "]\n";
}
You'd have to figure out where to store the index. This effectively allows you to add custom state to the stream (note that this would not be thread-safe out-of-the-box). Every function that wants indentation should add the requested indentation to the stream, and subtract it again when it is done. You could make sure this always happen by using a guard to add/subtract the desired indent (IMHO this is more elegant than using a manipulator):
class indent_guard {
public:
indent_guard(int level, std::ostream& stream, int index)
: level(level),
stream(stream),
index(index)
{
stream.iword(index) += level;
}
~indent_guard() {
stream.iword(index) -= level;
}
private:
int level;
std::ostream& stream;
int index;
};
You could use it like this:
void some_func() {
indent_guard(2, std::cout, index);
// all output inside this function will be indented by 2 spaces
some_func(); // recursive call - output will be indented by 4 spaces
// here it will be 2 spaces again
}
Not so good way to do this is to add a global variable, which tells the indentation. Something like this :
std::string OwnClassIndentation;
std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
oStream << "[SomeMember1:" << OwnClassIndentation << iOwnClass._ownMember1 << "]\n";
oStream << "[SomeMember2:" << OwnClassIndentation << iOwnClass._ownMember2 << "]\n";
}
And then set it as appropriate.
You can make your own stream class that has an indentation variable and override the endl for that class, inserting the indentation.
I want to derive a stringstream so that I can use the operator<< to construct a message which will then be thrown. The API would look like:
error("some text") << " more text " << 42 << std::endl;
This should do a
throw "some text more text 42"
So what I did is make an errorbuf (inheriting from streambuf) which overloads the 'overflow' method and then create an ostream(&errorbuf). I wonder if I shouldn't instead inherit from basic_ostringstream or something...
You could probably make it easier by doing something like:
class error_builder
{
public:
error_builder(const std::string& pMsg = "")
{
mMsg << pMsg;
}
~error_builder(void)
{
throw std::runtime_error(mMsg.str());
}
template <typename T>
error_builder& operator<<(const T& pX)
{
mMsg << pX;
return *this;
}
private:
std::stringstream mMsg;
};
error_builder("some text") << " more text " << 42 << std::endl;
Note that you shouldn't throw strings like you are, hence I used std::runtime_error. All exceptions should derive from std::exception, which runtime_error does, that way all meaningful exceptions can be caught with const std::exception&.
This works because the temporary lives until the end of the full expression.
Some operators are missing from GMan's solution.
class error {
public:
explicit error(const std::string& m = "") :
msg(m, std::ios_base::out | std::ios_base::ate)
{}
~error() {
if(!std::uncaught_exception()) {
throw std::runtime_error(msg.str());
}
}
template<typename T>
error& operator<<(const T& t) {
msg << t;
return *this;
}
error& operator<<(std::ostream& (*t)(std::ostream&)) {
msg << t;
return *this;
}
error& operator<<(std::ios& (*t)(std::ios&)) {
msg << t;
return *this;
}
error& operator<<(std::ios_base& (*t)(std::ios_base&)) {
msg << t;
return *this;
}
private:
std::ostringstream msg;
};
I'll trot out my favourite macro again here:
#define ATHROW( msg ) \
{ \
std::ostringstream os; \
os << msg; \
throw ALib::Exception( os.str(), __LINE__, __FILE__ ); \
} \
In use:
ATHROW( "Invalid value: " << x << " should be " << 42 );
the exception type is from my own library, but I think you get the idea. This is much simpler than deriving your own stream class, and avoids lots of nasty complications with op<<().
I usually just create my own exception classes. You only have to override what() and can provide as many constructors as you like. To build up the error message, just use vasprintf (if available) or std::ostringstream like above.
Here's an example:
class CustomException : public std::exception {
private:
const std::string message;
public:
CustomException(const std::string &format, ...) {
va_list args;
va_start(args, format);
char *formatted = 0;
int len = vasprintf(&formatted, format.c_str(), args);
if (len != -1) {
message = std::string(formatted);
free(formatted);
} else {
message = format;
}
va_end(args);
}
const char *what() const {
return message.c_str();
}
};
If you don't have vasprintf, you can also use vsnprintf with a buffer on the stack...
How can I derive a class from cout so that, for example, writing to it
new_cout << "message";
would be equivalent to
cout << __FUNCTION__ << "message" << "end of message" << endl;
class Log
{
public:
Log(const std::string &funcName)
{
std::cout << funcName << ": ";
}
template <class T>
Log &operator<<(const T &v)
{
std::cout << v;
return *this;
}
~Log()
{
std::cout << " [end of message]" << std::endl;
}
};
#define MAGIC_LOG Log(__FUNCTION__)
Hence:
MAGIC_LOG << "here's a message";
MAGIC_LOG << "here's one with a number: " << 5;
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl)
This has the advantage that you can disable all debug messages at once when you're done
#define debug_print(message) ()
Further from Mykola's response, I have the following implementation in my code.
The usage is
LOG_DEBUG("print 3 " << 3);
prints
DEBUG (f.cpp, 101): print 3 3
You can modify it to use FUNCTION along/in place of LINE and FILE
/// Implements a simple logging facility.
class Logger
{
std::ostringstream os_;
static Logger* instance_;
Logger();
public:
static Logger* getLogger();
bool isDebugEnabled() const;
void log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const;
std::ostringstream& getStream()
{ return os_; }
};
void Logger::log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const
{
std::cout << logLevelEnumToString(l) << "\t(" << fileName << ": " << lineno << ")\t- " << os.str();
os.str("");
}
#define LOG_common(level, cptext) do {\
utility::Logger::getLogger()->getStream() << cptext; \
utility::Logger::getLogger()->log(utility::level, utility::Logger::getLogger()->getStream(), __FILE__, __LINE__); \
} while(0);
enum LogLevelEnum {
DEBUG_LOG_LEVEL,
INFO_LOG_LEVEL,
WARN_LOG_LEVEL,
ERROR_LOG_LEVEL,
NOTICE_LOG_LEVEL,
FATAL_LOG_LEVEL
};
#define LOG_DEBUG(cptext) LOG_common(DEBUG_LOG_LEVEL, cptext)
#define LOG_INFO(cptext) LOG_common(INFO_LOG_LEVEL , cptext)
#define LOG_WARN(cptext) LOG_common(WARN_LOG_LEVEL , cptext)
#define LOG_ERROR(cptext) LOG_common(ERROR_LOG_LEVEL, cptext)
#define LOG_NOTICE(cptext) LOG_common(NOTICE_LOG_LEVEL, cptext)
#define LOG_FATAL(cptext) LOG_common(FATAL_LOG_LEVEL, cptext)
const char* logLevelEnumToString(LogLevelEnum m)
{
switch(m)
{
case DEBUG_LOG_LEVEL:
return "DEBUG";
case INFO_LOG_LEVEL:
return "INFO";
case WARN_LOG_LEVEL:
return "WARN";
case NOTICE_LOG_LEVEL:
return "NOTICE";
case ERROR_LOG_LEVEL:
return "ERROR";
case FATAL_LOG_LEVEL:
return "FATAL";
default:
CP_MSG_ASSERT(false, CP_TEXT("invalid value of LogLevelEnum"));
return 0;
}
}
For logging purposes I use something like
#define LOG(x) \
cout << __FUNCTION__ << x << endl
// ...
LOG("My message with number " << number << " and some more");
The problem with your approach is (as Mykola Golybyew explained) that FUNCTION is processed at compile time and would therefore always print the same name with a non-preprocessor solution.
If it's only for adding endl to your messages, you could try something like:
class MyLine {
public:
bool written;
std::ostream& stream;
MyLine(const MyLine& _line) : stream(_line.stream), written(false) { }
MyLine(std::ostream& _stream) : stream(_stream), written(false) { }
~MyLine() { if (!written) stream << "End of Message" << std::endl; }
};
template <class T> MyLine operator<<(MyLine& line, const T& _val) {
line.stream << _val;
line.written = true;
return line;
}
class MyStream {
public:
std::ostream& parentStream;
MyStream(std::ostream& _parentStream) : parentStream(_parentStream) { }
MyLine getLine() { return MyLine(parentStream); }
};
template <class T> MyLine operator<<(MyStream& stream, const T& _val) {
return (stream.getLine() << _val);
}
int main()
{
MyStream stream(std::cout);
stream << "Hello " << 13 << " some more data";
stream << "This is in the next line " << " 1 ";
return 0;
}
Note, that it's important not to return references from the operator functions. Since the MyLine should only exist as a temporary (for its destructor triggers the writing of the endl), the first object (returned by the getLine() function in MyStream) would be destructed before the second operator<< is called. Therefore the MyLine object is copied in each operator<< creating a new one. The last object gets destructed without being written to and writed the end of the message in its destructor.
Just try it out in the debugger to understand whats going on...
You have to override operator<<(), but you even don't have to subclass std::cout. You may also create a new object or use existing objects like that.
You could also override the operator. It will allow you to call another function or prefix/suffix anything that's going to leave the output buffer with whatever you wish: In your case, you'd have it output a specific string.