Design by Contract & why not also a Quick and “dirty” Logger?!

I mentioned earlier my thoughts on a tailor-made a KISS style logger. Design-by-Contract is also something that keeps popping up. If a really messed up error happens just a simple assert won’t do since you want to use your logger to log the messed up error and then do a safe and controlled shutdown, sometimes followed by a restart (depending on type of system of course)

The “dirty” in Quick and “dirty” Logger comes from the use of c++ macros. In this case even som g++ specific macros. I’m no fan of macros but for this specific purpose it’s perfect.

After going through some old code of mine and being inspired I ended up with not the stream like syntax that I enjoyed with google glog but a printf like syntax. I still like the streamish syntax LOG(level) << "Hello this is my log message" but the familiarity of the printf syntax and that it was a little faster to wring together made me postpone it (for now).

… So instead it turned out similar to
LOG(level,”Hello this is my log message”);
LOG_N(level,”Hello this is my log’s %d st %s message”, 1, “very cool” );
// ie. : “Hello this is my log’s 1 st very cool message”

It all turned out very simple and very easy to code up and to modify for later. The bare bone content of it is as following.


LOG(WARNING, “bla bla bla”);
LOG_N(INFO, “Text like this:%d, or this text:%s”, some_value, some_text);
The Design-By-Contract is very similar
CHECK_1(boolean_expression, “bla bla bla”);
CHECK_N(boolean_expression, “Text like this:%d, or this text:%s”, some_value, some_text);

For the LOG it’s nifty to have a level so that you can differentiate (in resulting log files or turning on/off levels). To get a nice compilation error if the wrong level is used the ## flag can be used to concatenate the level with. Let me show you in “reading easy order” not “code order”

const unsigned int INFO = 0, WARNING = 1;
#define LOG(level, message)
#define KLOG_INFO klog::LogMessage(__FILE__, __LINE__, INFO)
// i.e. KLOG_##level is concatenated to KLOG_INFO (when ‘level’ is INFO)
#define LOG_N(level, printf_like_message, …), __VA_ARGS__)
#define KLOG_N_WARNING klog::LogMessage(__FILE__, __LINE__, WARNING)
…etc for KLOG_N_INFO
namespace klog
class LogMessage
LogMessage(const std::string& file, const int line, const int level):
void save(const std::string &message){…}
void save(const char* printf_like_message, …)
{… // whatever that makes the ‘save’ bring the log from here to some file storage later on …}


Getting the Design-by-Contract minimum stuff in order is just as easy

#define CHECK(boolean_expression) \
if (false == (boolean_expression)) \
klog::HandleSoftwareError(__FILE__, __LINE__, __PRETTY_FUNCTION__, #boolean_expression,””);
likewise as LOG_N for CHECK_N and the variadic arguments

So, there you go. The basics for the API of your own logger or your own design-by-contract handler. Of course putting it all together in the end requires much more work in the area of timestamps, thread safety and FIFO order for logs even between threads, maybe even a stack trace for when CHECK(..false..) is called.

Maybe I’ll update this blog later or post a link to a real code example … if you can’t wait till then just e-mail me or comment on the post and I’ll give you a preview.

Update 9th, February, 2012. See the finished result G2Log @ CodeProject

About kjellkod

Software Engineer by trade, (former?) Martial Artist and Champion by strong will and small skill... and a Swede by nationality :)
This entry was posted in C++, Software Engineering. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s