I want to design a logging function with the following characteristics:
- based on std::string rather than char*
- supports variable number of variables, like printf
- accepts as first parameter a severity level
- avoids formatting overhead when severity level is below logging level
- as simple as printf, or nearly so
I'm inclined to use boost::format because of its automatic type conversion. But here are some problems I see:
Its syntax is a little awkward: format("Mgr %s on pid %d is in state %s" % mgr % pid % s) is a little hard on the eyes (the list nature of the variables isn't as evident without commas). A log invocation would look like this:
mylog(INFO, format("Mgr %s on pid %d is in state %s" % mgr % pid % s));
What's worse, is it even possible to implement mylog() to check if we're logging INFO messages before the format object is constructed?
The other approach I thought about, which looks closer to printf, would be
mylog(INFO, "Mgr %s on pid %d is in state %s", mgr, pid, s);
or even
mylog_info("Mgr %s on pid %d is in state %s", mgr, pid, s);
The implementation would be something like:
mylog(int severity, string pattern, ...) {
if (severity >= LOGLEVEL) {
boost::format fmt(pattern);
for parm /* remaining parameters */ {
fmt % parm; // feed into format one at a time
}
}
}
This certainly defers construction of the format object until it's needed. But from what I can tell, there's no way, when traversing a variable argument list, to tell when you've reached the end!
Can someone suggest a syntactically simple technique of accomplishing this?
Note: I have g++ 4.4, which does not support all of c++11 (although it does support variadic templates)
You can use variadic templates and recursion.
A solution could be implemented as something along these lines: