Quick and simple debug stream for C++

by Ben

Ever need to set up a quick and simple debug/logging stream for your application without having to deal with large frameworks like log4cpp or *shudder* log4cxx? There’s also libcwd, which seems really neat, but also very large.

I didn’t want to use all that. I just needed a simple way to filter my output using streams without having if(…) blocks scattered all over the place. Here was my solution (I can’t remember if I came up with this on my own, or pawned it from someone else…if nothing else, I at least used the reference documentation for the boost Iostreams library). Read on to see what I did.

First, the header:

// debug.hpp
#ifndef _DEBUG_H_
#define _DEBUG_H_

#include 
#include 
#include 

#include 

// this defines a struct named options and
// an instance of it called "opts"
#include "main.hpp"  

struct nullstream : std::ostream
{
  struct nullbuf : std::streambuf
  {
    int overflow(int c) { return traits_type::not_eof(c); }
  } _sbuf;

  nullstream()
    : std::ios(&_sbuf), std::ostream(&_sbuf) {}
};

template
nullstream& operator<<(nullstream& ns, T)
{ return ns; }

extern options opts;
extern nullstream null;

std::ostream& debug(short level);
std::ostream& warn();
std::ostream& error();

#endif

Then the implementation:

// debug.cpp
#include "debug.hpp"

nullstream null;

std::ostream& debug(short level)
{
  if(opts.verbose < level)
    return null;

  return std::cout;
}

std::ostream& warn()
{
  return std::cout << "[warn] ";
}

std::ostream& error()
{
  return std::cerr << "[error] ";
}

Very quick, very simple. Usage is just as easy. Instead of using std::cout like you often would, you just use debug(level), warn(), and error() in its place.

if(/*something important happens*/)
  debug(0) << "whatever" << std::endl;

if(/*something interesting happens*/)
  {
    debug(1) << "something very interesting"
                 << std::endl;
    debug(2) << "something less interesting"
                 << std::endl;
    debug(7) << "the user should never know about this"
                 << std::endl;
    /* ... */
   }

if(/* something bad but not fatal happens */)
  {
    warn() << "whoops, you messed up..."
              << "that's ok, continuing."
              << std::endl;
  }

if(/* something fatal happens */)
  error() << "serious fubar.  quitting."
            << std::endl;