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.
Related
I have a logging class in C++. It's a singleton with multithreading support.
What I wanted to achieve (and mainly did):
have a generic logger class
singleton
use it with stream insertion operator not as a function call
The class writes in a std::stringstream and on std::endl it flushes the std::stringstream content to file. A big drawback is that std::endl is required once and onlny once per call for everything to work correctly in a multithreading app. not sure if it's a good approach, but it's ok for now and in my case I can go with this drawback
My problem is that a call to std::setfill() when logging will deadlock. It seems that this call is not sent to my Logger class and is executed outside its critical section.
Can I achieve this? A logger class with full support for manips?
Log Calls
LOGI << "Some message " << aVariable << std::endl; // OK
LOGI << std::setw(20) << var << std::endl // OK
LOGI << std::setfill('-') << std::setw(50) << var << std::endl; // NOT OK because of setfill() call !!!!
Class Sample code
#define LOGFATAL Logger::GetLogger(LOGLEVEL_FATAL, __FUNCTION__)
#define LOGE Logger::GetLogger(LOGLEVEL_ERROR, __FUNCTION__)
#define LOGW Logger::GetLogger(LOGLEVEL_WARN, __FUNCTION__)
#define LOGI Logger::GetLogger(LOGLEVEL_INFO, __FUNCTION__)
#define LOGD Logger::GetLogger(LOGLEVEL_DEBUG, __FUNCTION__)
#define LOGV Logger::GetLogger(LOGLEVEL_VERBOSE, __FUNCTION__)
class Logger
{
public:
static void Initialize(const std::string& _logFile, const std::string& _logLevel)
{
isInitialized = true;
logFileName = _logFile;
logLevel = GetLogLevel(_logLevel);
}
static Logger& GetLogger(LogLevel l, const std::string& funcName)
{
if(isInitialized)
csFile->lock();
msgLogLevel = l;
functionName = funcName;
return GetLogger();
}
typedef std::ostream& (*ManipFn)(std::ostream&);
typedef std::ios_base& (*FlagsFn)(std::ios_base&);
template<class T>
Logger& operator<<(const T& output)
{
if (!isInitialized)
return *this;
m_stream << output;
return *this;
}
Logger& operator<<(const ManipFn manip)
{
if (!isInitialized)
return *this;
manip(m_stream);
if (manip == static_cast<ManipFn>(std::flush) ||
manip == static_cast<ManipFn>(std::endl))
{
// flush the stream and unlock the mutex
this->flush();
csFile->unlock();
}
return *this;
}
Logger& operator<<(const FlagsFn manip) /// setiosflags, resetiosflags
{
manip(m_stream);
return *this;
}
...
static Logger& GetLogger()
{
static Logger instance;
return instance;
}
Let me know if more information is needed
I missed my own words and my own code problems and limits (of which I was aware when I posted the question).
My mistake was not to post the initial code which deadlocked my process. Here's the code:
LOGV << std::setfill('-') << std::setw(206) << '-' << std::endl;
LOGV << std::setfill(' ');
To quote myself "A big drawback is that std::endl is required once and onlny once per call for everything to work correctly in a multithreading app".
So the fix for my problem is LOGV << std::setfill('-') << std::setw(206) << '-' << std::setfill(' ') << std::endl;
Sorry for not checking in further, and for wasting anyone's time.
Suppose that I want to create a stream that would perform an action at the end of the statement, so that
myStream << "Hello, " << "World!";
would print "Hello, World!\n" in one shot. Not "Hello, \nWorld!\n" and not "Hello, World!", but "Hello, World\n", as if ; would trigger appending \n and flushing the buffers.
The rationale for that is a stream class that writes to both stdout and a logfile, with the logfile entries having certain prefixes and suffixes.
For example, if my target was HTML I would want this code:
myStream << "Hello, " << "World!";
myStream << "Good bye, " << "cruel World!";
to print like this:
<p>Hello, World!</p>
<p>Good bye, cruel World!</p>
and not like this:
<p>Hello, </p><p>World!</p>
<p>Good bye, </p><p>cruel World!</p>
Now, if I implement LogStream sort of like this:
LogStream & LogStream::operator<<( const std::string & text );
I won't be able to distinguish between << in the middle of the statements from the ones in the beginning/ending of the statements.
If I implement LogStream sort of like this:
LogStream LogStream::operator<<( const std::string & text );
and try to massage the input in the destructor I would get multiple destructors at once at the end of the block.
Finally, I can implement this my requiring endl at the end of each statement, but I'd rather not bother the caller with the necessity to do so.
Thus the question: how one implements such a stream in a caller-transparent fashion?
I implemented something like this once for a custom logging system. I created a class that buffered input and then its destructor flushed the buffer to my log file.
For example:
#include <iostream>
#include <sstream>
#include <string>
class LogStream
{
private:
std::stringstream m_ss;
void flush()
{
const std::string &s = m_ss.str();
if (s.length() > 0)
{
std::cout << s << std::endl;
logfile << "<p>" << s << "</p>" << std::endl;
}
}
public:
LogStream() {}
~LogStream()
{
flush();
}
template <typename T>
LogStream& operator<<(const T &t)
{
m_ss << t;
return *this;
}
template <typename T>
LogStream& operator<<( std::ostream& (*fp)(std::ostream&) )
{
// TODO: if fp is std::endl, write to log and reset m_ss
fp(m_ss);
return *this;
}
void WriteToLogAndReset()
{
flush();
m_ss.str(std::string());
m_ss.clear();
}
};
For single statements that flush on the final ;, each message would use a new instance of the class:
LogStream() << "Hello, " << "World!";
LogStream() << "Good bye, " << "cruel World!";
To allow multiple statements to write to a single message, create the object and do not let it go out of scope until the last statement is done:
{
LogStream myStream;
myStream << "Hello, ";
myStream << "World!";
}
{
LogStream myStream;
myStream << "Good bye, ";
myStream << "cruel World!";
}
To reuse an existing instance for multiple messages, tell it to flush and reset in between each message:
{
LogStream myStream;
myStream << "Hello, " << "World!";
myStream.WriteToLogAndReset();
myStream << "Good bye, " << "cruel World!";
}
I like this approach because it gives the caller more flexibility in deciding when each message is ready to be written to the log file. For instance, I use this to send multiple values to a single log message where those values are obtained from decision-making code branches. This way, I can stream some values, make some decisions, stream some more values, etc and then send the completed message to the log.
The line:
myStream << "Hello, " << "World!";
Is actually multiple statements. It's equivalent to:
ostream& result = myStream << "Hello, ";
result << "World!";
There are some tricks to do what you want by returning an unnamed temporary object (which are destroyed at the end of the full-expression). Here is some example code.
I have a little code that I haven't gotten round to doing anything constructive with that I think is doing what you're asking.
It works by using a proxy class (log_buffer) to build up the string in a std::stringstream object. At the end of the expression the log_buffer proxy object calls the main log_writer
object to process the whole line contained in the std::stringstream.
class log_writer
{
// ultimate destination
std::ostream* sink = nullptr;
// proxy class to do the << << << chaining
struct log_buffer
{
log_writer* lw;
std::stringstream ss;
void swap(log_buffer& lb)
{
if(&lb !=this)
{
std::swap(lw, lb.lw);
std::swap(ss, lb.ss);
}
}
log_buffer(log_writer& lw): lw(&lw) {}
log_buffer(log_buffer&& lb): lw(lb.lw), ss(std::move(lb.ss)) { lb.lw = nullptr; }
log_buffer(log_buffer const&) = delete;
log_buffer& operator=(log_buffer&& lb)
{
swap(lb);
return *this;
}
log_buffer& operator=(log_buffer const&) = delete;
// update the log_writer after the last call to << << <<
~log_buffer() { if(lw) lw->add_line(ss); }
template<typename DataType>
log_buffer operator<<(DataType const& t)
{
ss << t;
return std::move(*this);
}
};
void swap(log_writer& lw)
{
if(&lw != this)
{
std::swap(sink, lw.sink);
}
}
public:
log_writer(std::ostream& sink): sink(&sink) {}
log_writer(log_writer&& lw): sink(lw.sink) { lw.sink = nullptr; }
log_writer(log_writer const&) = delete;
log_writer& operator=(log_writer&& lw)
{
swap(lw);
return *this;
}
log_writer& operator=(log_writer const&) = delete;
// output the final line
void add_line(std::stringstream& ss)
{
// Do any special line formatting here
if(sink) (*sink) << ss.str() << std::endl;
}
template<typename DataType>
struct log_buffer operator<<(DataType const& data)
{
return std::move(log_buffer(*this) << data);
}
};
int main()
{
std::ofstream ofs("test.log");
log_writer lw1(ofs);
log_writer lw2(std::cout);
lw1 << "lw1 " << 2.93 << " A";
lw2 << "lw2 " << 3.14 << " B";
std::swap(lw1, lw2);
lw1 << "lw1 " << 2.93 << " C";
lw2 << "lw2 " << 3.14 << " D";
}
I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.
I created my own std::cout-like object that writes both to std::cout and to a log file.
I'm currently defining it like this in a header file, but I'm getting unused variable warnings.
Header file <MyLib/Log.h>
static LOut { };
static LOut lo;
template<typename T> inline LOut& operator<<(LOut& mLOut, const T& mValue)
{
std::string str{toStr(mValue)};
std::cout << str;
getLogStream() << str;
return mLOut;
}
Usage:
#include <MyLib/Log.h>
...
lo << "hello!" << std::endl;
Should lo be static? Should lo be extern?
Kudos for explaining the correct way of declaring a cout-like object and showing how the main standard library implementations do it.
Edit: by cout-like object, I mean a global variable that is always available after including the corresponding header.
std::cout is simply declared as follows:
namespace std {
extern ostream cout;
}
It is a regular global variable; you can do the same thing yourself. Put an extern declaration of your variable in a header; then define the same variable in a source file and link it to your application:
// mylog.h
extern MyLog mylog;
// mylog.cpp
MyLog mylog(someparams);
First, I'm not too sure what you mean be a cout-like object?
Perhaps an std::ostream.
Anyway, the usual way of doing this is to use a filtering
streambuf. Just write a streambuf which forwards to a log file,
in addition to the usual place, and insert it where ever you
want:
class LoggingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ofstreambuf myLogFile;
std::ostream* myOwner;
protected:
int overflow( int ch )
{
myLogFile.sputc( ch ); // ignores errors...
return myDest->sputc( ch );
}
public:
LoggingOutputStreambuf(
std::streambuf* dest,
std::string const& logfileName )
: myDest( dest )
, myLogFile( logfileName.c_str(), std::ios_base::out )
, myOwner( nullptr )
{
if ( !myLogFile.is_open() ) {
// Some error handling...
}
}
LoggingOutputStreambuf(
std::ostream& dest,
std::string const& logfileName )
: LoggingOutputStreambuf( dest.rdbuf(), logfileName )
{
dest.rdbuf( this );
myOwner = &dest;
}
~LoggingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
};
(This is C++11, but it shouldn't be hard to modify it for
C++03.)
To use, you could use something like:
LoggingOutputStreambuf logger( std::cout );
// ...
All output to std::cout will be logged until logger goes out
of scope.
In practice, you'll likely use something more complicated than a
filebuf for logging, since you may want to insert time stamps
at the start of each line, or systematically flush at the end of
each line. (Filtering streambufs can take care of those issues
as well.)
std::cout-like object that writes both to std::cout and to a log file
Maybe boost.iostreams would be sufficient?
#include <iostream>
#include <fstream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
namespace io = boost::iostreams;
int main()
{
typedef io::tee_device<std::ostream, std::ofstream> teedev;
typedef io::stream<teedev> LOut;
std::ofstream outfile("test.txt");
teedev logtee(std::cout, outfile);
LOut mLOut(logtee);
mLOut << "hello!" << std::endl;
}
Simply sending the input value right out to cout didn't work for me, because I wanted to add headers and info to the log output.
Also, I had my static Debug class in which to wrap the Log stream.
This is the way I managed to do this, I hope it's useful. I'm somehow a newbye to c++, so feel free to tell me if something is wrong :)
#include <iostream>
#include <sstream>
#include <ostream>
enum class DebugLevel {
INFO,
WARNING,
ERROR
};
class Debug {
public:
/* other Debug class methods/properties
...
*/
// out stream object
static struct OutStream {
std::ostringstream stream;
DebugLevel level = DebugLevel::INFO;
public:
// here you can add parameters to the object, every line log
OutStream& operator()(DebugLevel l) {
level = l;
return *this;
}
// this overload receive the single values to append via <<
template<typename T>
OutStream& operator<<(T&& value) {
stream << value;
return *this;
}
// this overload intercept std::endl, to flush the stream and send all to std::cout
OutStream& operator<<(std::ostream& (*os)(std::ostream&)) {
// here you can build the real console log line, add colors and infos, or even write out to a log file
std::cout << __TIME__ << " [" << (int)level << "] " << stream.str() << os;
stream.str(""); // reset the string stream
level = DebugLevel::INFO; // reset the level to info
return *this;
}
} Log;
};
Debug::OutStream Debug::Log; // need to be instantiaded only because I use a static Debug class
int main() {
Debug::Log(DebugLevel::ERROR) << "Hello Log! " << 2 << " " << __FUNCTION__ << std::endl;
Debug::Log << "Hello Log! " << 0xFA << std::endl; // NB: this way the debugLevel is default
return 0;
}
In one of my projects, I wrote wrapper for std::cout.
It looks something like this:
struct out_t {
template<typename T>
out_t&
operator << (T&& x) {
std::cout << x;
// log << x;
return *this;
};
};
out_t out;
out << 1;
For complete code look for struct out in io.h
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.