We have a log implementation that's based on std::ostream with a custom stream buffer. We implement our application's instance of the log class via a Schwarz counter.
To avoid coupling our lower level classes to our log implementation, we can pass a reference to a std::ostream. In this way our lower level classes can log to std::cout, std::cerr or to the instance created via the Schwarz counter.
I have one problem with this. The log implementation sets its severity via an overload of the stream operator:
// Overload the << operator to set the log message severity
inline CLogStream& operator << (CLogStream& myLogStream, eMsgType::type msgTypeCurrent)
{
myLogStream.SetMsgTypeCurrent(msgTypeCurrent);
return ( myLogStream ) ;
}
This allows us to use the logger like this:
CLog::Main << CLog::MSG_FATAL << "Fatal error" << std::endl;
I'd like to create a reference to our app's instance of the log which is locked to a particular severity. That way, I can pass our utility classes two std::ostream references. One of these would be used for normal reporting and the other for error reporting. These could be set to std::cout and std::cerr, or to some kind of object referring to our log object instance.
Unfortunately the std::ostream operator << aren't virtual as far as I'm aware, so I'm not sure how to design such an object.
Any thoughts?
iostream has virtual member functions (specifically, ~ios_base) so you can perform a dynamic_cast in the operator<<:
inline std::ostream &operator<<(std::ostream &os, eMsgType::type msgTypeCurrent) {
if (CLogStream *myLogStream = dynamic_cast<CLogStream *>(&os)) {
myLogStream->SetMsgTypeCurrent(msgTypeCurrent);
} else {
os << "TYPE: " << static_cast<typename std::underlying_type<eMsgType::type>
::type>(msgTypeCurrent) << ": ";
}
return os;
}
If the setting of the severity is persistent, such that both tese lines result in a log entry with fatal severity
CLog::Main << CLog::MSG_FATAL << "Log entry 1: " << some_data << std::endl;
CLog::Main << "Log entry 2: " << some_other_data << std::endl;
then your logging class is already correctly designed to be passed along as a generic ostream&. You just need separate logger instances for the different log-levels that are supported by the utility classes.
This is written under the assumption that the logger class has been inherited from ostream to take advantage of the existing operator<< overloads.
In that case, the operator<< for some_data and some_other_data are already completely unaware that the output goes to a log stream.
Read about ios_base::iword(). It gives you access to an array of long values in the stream object that you can use to store things like flags and special values.
Related
I am looking for a way to use an ostream with my custom string class and overload the operator << to stream to the buffer which i can then flush to anywhere i want (in my case its just gonna be printed in a window)
I'm reasonably new to the inner workings of iostream's but from my understanding the method i've seen of making std::stringbuf a base of my custom stringstream would not work because the stringbuf deals with the std::string.
in essence i want to able to do this (or similar):
MyStringClass string
MyOutput << "hello" << string << "World" << std::endl;
Where MyOutput can be changed to print to anywhere i want.
Thank you.
Not a problem. Define your class, and within it's definition add an ostream& operator<<(const String&);.
Inside that operator, you can code whatever handling you want (look at std::string for inspiration)
When you stream variables to an output stream such as cout, type conversion is automatic. What I'm trying to figure out is how to do this via a function call, for example:
inline void DEBUG(ostream& s) // Don't know if this prototype is appropriate
{
cout << s;
}
main()
{
int i = 5;
DEBUG("The value is: " << i << endl); // This doesn't compile
DEBUG("The value is: " + i + endl); // Neither does this
}
I found similar questions on here, but they all involve passing the stream object as a parameter, whereas I'm trying to pass the "streamed data" to a function that already has the stream object, so it's the other way round. Is this even possible? I don't want to resort to explicit type conversions. I also found this question, but I really don't want to write a whole logger class if I can avoid it.
At the moment I'm implementing it as a macro, which works, but I'd rather use an inline function if possible.
#define DEBUG(s) (cout << s)
Of course it does not compile. There are many reasons for that.
First, Operator << is not defined for standard streams, and you are trying to do exactly that: stream stream into stream in your DEBUG(). (Pun intended).
Second, operator << is not defined for string literals, and you are trying to invoke it here:
"The value is: " << i
+ is not defined for literals either, by the way.
To achieve the semantic you want to see, you will have to start with the stream. String literal need to be converted to stream first, and than you can apply << to it. This is ONLY way to achieve what you want.
Edit:
Now since I understand the rationale, I can give a better answer. There are many ways how people are trying to segregate different levels of debugging uniformely, and there are several libraries aiming for that (log4cpp, boost.log to name just few). Before you start implementing your own logging, I would definitely suggest looking into those. There is much more to the good logging than just debug levels.
If, for any reason, you want to use your own homebrew, here are the couple of recepies you might explore:
Use your own logger class (one of the very rare examples, close to
the single one! where Singleton is appropriate). You can than set the
logging level in the beggining of your application, and than just
call Logger::debug() << ...
Enrich above solution with macros. The problem with functions is that, unlike macros, they loose context. So if you want to log file and line number of the logging invocation (and you usually do!), you might want to do LOG_DEBUG << ...; here LOG_DEBUG would expand into something like Logger::debug() << __FILE__ << ":" << __LINE__ << ....
Once you've done this, you will see that sometimes you call other functions inside the << chain. At this point you might realize that those functions would be called regardless of your debug level, and might think you do not want to call them when debugging is not enabled (something along the lines LOG_DEBUG << " Object now is " << object.serialize(); So you will want to enrich the LOG_DEBUG macro to not execute anything when debug level does not match.
And the saga continues... Ready to use the library?
Well, what (at least some) logging libraries would do is create a temporary proxy object that would act as a stream:
#include <iostream>
struct LoggerProxy {
LoggerProxy(const char* file, int line)
{
std::cout << "File " << file << ", line " << line << ": ";
}
template<typename T>
LoggerProxy& operator<<(T&& t)
{
std::cout << t;
return *this;
}
};
#define LOG_DEBUG LoggerProxy{__FILE__, __LINE__}
int main()
{
LOG_DEBUG << "Value is: " << 4;
}
You can do a lot of fancy stuff with this, such as debug level checks, output to different streams or multiple backends (such as simultaneous output to std::cout/cerr and log file) and many more.
I have a custom output class that has two std::ostream members that serve different purposes. Either stream is used depending upon how the output class is configured. In some instances, the two streams are chained together. A grossly simplified version of the class is below. I can provide some more details if needed.
class c_Output
{
public:
c_Output (bool x_useA) : m_useA(x_useA) { /* setup m_stream[AB] here */ };
~c_Output ();
inline std::ostream& stream () { return (m_useA ? m_streamA : m_streamB); };
private:
bool m_useA;
std::ostream m_streamA;
std::ostream m_streamB;
}
I know how to write stream operators for classes that I wish to stream to/from std::cout, std::cin, or any other std::iostream, but I am struggling to write stream operators where a c_Output instance serves as the lhs instead of a std::ostream instance.
Right now, I am able to get away with:
c_Output l_output;
uint64_t l_value = 0xc001c0de;
l_output.stream() << std::hex << std::setw(16) << std::setfill('0') << l_value;
c_Output::stream() returns the appropriate std::ostream&, so this behaves just as expected.
I would like to rewrite the above as:
c_Output l_output;
uint64_t l_value = 0xc001c0de;
l_output << std::hex << std::setw(16) << std::setfill('0') << l_value;
I have attempted several different versions of defining operator<< based on examples I have seen here on StackOverflow and the greater web to no avail. The latest version looks like this:
// in header
class c_Output
{
...
friend c_Output& operator<< (c_Output& x_output, std::ostream& x_stream);
...
}
// in source
c_Output&
operator<< (c_Output& x_output, std::ostream& x_stream)
{
x_output.stream() << x_stream;
return x_output;
}
The setup of the arguments is intended to mirror the standard stream operator overload. This setup gives me compile issues such as:
error: no match for 'operator<<' in 'l_output << std::hex'
note: candidates are: c_Output& operator<<(c_Output&, std::ostream&)
I have stripped away all the file and line information, but it gets the point across. I am obviously getting the type for the rhs of the operator incorrect. What is the correct type and/or correct means of implementing the stream operator as desired?
There is also a complementary c_Input class that has a similar requirement, but adapting the answer for c_Output should be trivial.
The type of std::hex is std::ios_base& (*)(std::ios_base&). Change your operator signature to:
c_Output& operator<< (c_Output& x_output, std::ios_base& (*x_stream)(std::ios_base&));
operator<< (c_Output& x_output, std::ostream& x_stream)
The only real problem is that std::hex isn't a std::ostream, and with your methods no overloaded << is available for it.
In order to support the usage of the hex modifier, you'll need another friend overload with parameters (c_Output&, ios_base& (*)(ios_base&)) (as hex is a pointer to function taking reference to ios_base returning reference to ios_base).
At the rate you're going, you'll need to also implement all the other << overloads as well. This is not a trivial task, but is necessary to masquerade as a std::ostream, with or without inheriting from it.
I have to extend the ofstream class to write a logging stream service.
The goal is to intercept each line, adding at the head of each one a customized text (date/time, severity, and so on).
Now, it's clear that I'm not a C++ guru, so I read a lot of documentation about this task, e.g.
http://www.angelikalanger.com/Articles/Topics.html#CPP
http://asmodehn.wordpress.com/2010/06/20/busy-c-coding-and-testing
http://gabisoft.free.fr/articles-en.html
The above articles suggest to write a custom stream buffer, but during porting of this concept on file streams I encountered a lot of difficulties.
Is there a simpler method to achieve this goal?
You don't need to write a custom stream buffer; the simplest and most straightforward way is to make a class you can send output to by giving it a templatized single argument operator<<():
template <typename T>
std::ostream& operator<<(const T& data_)
{
m_outstream << m_severity << "\t" << getTimeStamp() << "\t" << data_;
return m_outstream;
}
Where m_outstream is some type of std::ostream (std::ofstream, etc). m_severity and getTimeStamp() are examples of what you can insert (and you can create a bog standard two argument operator<<() to format and output the severity type to an ostream).
This then allows you to do things like:
myLogger << "failingFunction(" << argument <<
"): Could not do something." << std::endl;
and you will get output on m_outstream that looks like:
WARNING 2012-01-03 19:32 failingFunction("argument value"): Could not do something.
Beyond this, you will want a way to set the severity, which can be as simple as a method called on the logger class you added the templatized operator<<() to. If you want to get really fancy, you can write your own manipulator that acts much like setw() would on a std::ostream. See http://www.math.hkbu.edu.hk/parallel/pgi/doc/pgC++_lib/stdlibug/man_6665.htm for a primer on writing manipulators.
I am trying to do a simple logging library only for my own. I know there exists several once, but I have not found any header-only, small and very "c++" like logging library which fits into my application.
Currently I have the following syntax:
logger << debug << "A debug message" << end; //debug and end is my custom manipulators
I have implemented all necessary operator<< and it works great, specially when it have backward compatibility with std::ostream. But I wonder, just for efficiency if it is a why to stop evaluate anything if some message should not be logged (after debug in the example)? Making everything after the severity manipulator "disappear"?
Just now do I have the following code in short:
template <typename Type>
Logger & Logger::operator<<(const Type & message)
{
if(this->get_message_level() <= this->get_severity())
{
BOOST_FOREACH(std::ostream* stream, this->_sinks)
{
*stream << message;
}
}
return *this;
}
Logger & Logger::operator<< (Logger & (*pf)(Logger&))
{
return pf(*this);
}
Logger & debug(Logger& logger)
{
logger.lock();
logger.set_severity(7);
//...
return logger;
}
Logger & end(Logger& logger)
{
logger << std::endl;
logger.unlock();
return logger;
}
Thanks in advance.
You could do something as simple as
extern "C" bool want_log;
#define LOG(Arg) do { if (want_log) \
cout << __FILE__ << ":" << __LINE__ ": " << Arg << endl; } while(0)
and use it as LOG("x=" << x)
It can be a bit tricky, depending on what compromizes you're willing to
accept in the syntax. If you really want to support everything that
outputting to an ostream does, then the best you can do (as far as I
know) is a wrapper class, along the lines of:
class Logger
{
std::ostream* myDest;
public:
// Appropriate constructors...
template<typename T>
Logger& operator<<( T const& obj )
{
if ( myDest != NULL )
(*myDest) << obj;
return *this;
}
};
If logging is turned off (Logger::myDest == NULL), none of the
conversion code will execute, but you'll still evaluate each of the
arguments. In my experience, this is not usually an issue, since most
of the arguments are either string literals or a simple variable, but
it's not a total 0 cost. It also has the potential disadvantage that
the propagated type is not std::ostream& (although I've never found
this to be a problem in practice).
A somewhat tricker solution would be to use a macro along the lines of:
#define logger loggerInstance != NULL && (*loggerInstance)
This will still allow most of the actual uses with the same syntax
(because the && operator has very low precedence), but could fail in
cases where someone has tried to be too clever, and embedded the logging
output in a more complicated expression. In addition to not doing the
conversions, the arguments are not even evaluated if logging is turned
off.
Finally, if you accept a different syntax, you can write something like:
#ifndef NDEBUG
#define LOG(argList) logger << argList
#else
#define LOG(argList)
#endif
This requires the user to write LOG("x = " << x), instead of log <<
"x = " << x, and requires recompiling if you want to turn logging on,
but it is the only solution I know which has absolute 0 cost if logging
is turned off.
In my experience, most applications can support the first solution; in a
very few cases, you might want to use the second; and I've never seen an
application where performance required the third.
Note that even with the first, you'll probably want to use a macro to
get the logger instance, in order to automatically insert __FILE__ and
__LINE__, and that in the second, you'll probably still want to use a
wrapper class, in order to ensure a flush in the destructor; if the
application is multithreaded, you'll want the wrapper in all cases, in
order to make the entire sequence of output atomic.
You could check for the severity in the Logger & Logger::operator<< (Logger & (*pf)(Logger&)) operator and just return an "empty" logger that doesn't print anything in that case:
class EmptyLogger : public Logger {
template <typename Type>
Logger & Logger::operator<<(const Type & message) { return *this; }
};
EmptyLogger empty; // Can be global/static, it won't cause any race conditions as it does nothing
Logger & Logger::operator<< (Logger & (*pf)(Logger&))
{
if (logger.get_severity() < 5) // Replace with a proper condition
return empty;
return pf(*this); // What does pf() do? Aren't you returning reference to a temporary object?
}
Take a look at this article in dr dobbs about logging in c++:
http://drdobbs.com/cpp/201804215?pgno=2
This page addresses your particular concern but I'd recommend reading the whole article.
I implemented a logging system based on this article and was really pleased with it.