I have seen many loggers using operator<< to read log messages and write them on file:
template<typename T>
Logger& Logger::operator<<(Logger& l, const T& s) {
l.logStream << s;
return l;
}
...
Logger log;
log << "Test message " << 123;
I want the log to be flushed after "Test message" and 123 are written to the stream. However, rather than the user being in control of the flushing, I want the logger to flush the stream when it reaches the ;.
How can I do that?
Two solutions came to my mind, but I find both not acceptable:
I could put the new line at the beginning of each log message, so that the previous log is flushed, and in case of a crash all we loose is the current log.
operator<< could flush. But flushing on each invocation of << incurs a big performance penalty due to the number of write operations on disk (wearing). I want the flush to involve the whole message.
You can do that by returning a proxy object from
log::operator<<that has its ownproxy::operator<<which forwards tolog::operator<<, and flushes in its destructor.Something along the line of
output:
The proxy adds
hello proxyto the message in its destructor for illustration.The code you posted is somewhat bogus. Your
operator<<is a member function but has an additionalLogger¶meter. Thats not how you are going to getlog << "test";to work. Make it either a friend with the explicit argument or a member without.Moreoever, a templated
operator<<looks rather cool at first, but as soon as you want to handle iomanipulators, as egstd::flush, things get hairy, because most of them are function templates. I avoided passing the iomanipulator throughLogger::operator<<by letting the proxy pipe to the stream directly. You may want to make theLoggers stream private and the proxy a friend. Making io manipulators actually work with this approach I consider as beyond the scope of this question.For further reading I refer you to articles about RAII (resource acquisition is initialization).