Question

what is good practice for generating verbose output? currently, i have a function

bool verbose;
int setVerbose(bool v)
{
    errormsg = "";
    verbose = v;
    if (verbose == v)
        return 0;
    else
        return -1;
}

and whenever i want to generate output, i do something like

if (debug)
     std::cout << "deleting interp" << std::endl;

however, i don't think that's very elegant. so i wonder what would be a good way to implement this verbosity switch?

Was it helpful?

Solution

The simplest way is to create small class as follows(here is Unicode version, but you can easily change it to single-byte version):

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

enum log_level_t {
    LOG_NOTHING,
    LOG_CRITICAL,
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFO,
    LOG_DEBUG
};

namespace log_impl {
class formatted_log_t {
public:
    formatted_log_t( log_level_t level, const wchar_t* msg ) : fmt(msg), level(level) {}
    ~formatted_log_t() {
        // GLOBAL_LEVEL is a global variable and could be changed at runtime
        // Any customization could be here
        if ( level <= GLOBAL_LEVEL ) wcout << level << L" " << fmt << endl;
    }        
    template <typename T> 
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }    
protected:
    log_level_t     level;
    boost::wformat      fmt;
};
}//namespace log_impl
// Helper function. Class formatted_log_t will not be used directly.
template <log_level_t level>
log_impl::formatted_log_t log(const wchar_t* msg) {
    return log_impl::formatted_log_t( level, msg );
}

Helper function log was made template to get nice call syntax. Then it could be used in the following way:

int main ()
{
    // Log level is clearly separated from the log message
    log<LOG_DEBUG>(L"TEST %3% %2% %1%") % 5 % 10 % L"privet";
    return 0;
}

You could change verbosity level at runtime by changing global GLOBAL_LEVEL variable.

OTHER TIPS

int threshold = 3;
class mystreambuf: public std::streambuf
{
};
mystreambuf nostreambuf;
std::ostream nocout(&nostreambuf);
#define log(x) ((x >= threshold)? std::cout : nocout)

int main()
{
    log(1) << "No hello?" << std::endl;     // Not printed on console, too low log level.
    log(5) << "Hello world!" << std::endl;  // Will print.
    return 0;
}

You could use log4cpp

You can wrap your functionality in a class that supports the << operator which allows you to do something like

class Trace {
   public:
      enum { Enable, Disable } state;
   // ...
   operator<<(...)
};

Then you can do something like

trace << Trace::Enable;
trace << "deleting interp"

1. If you are using g++ you could use the -D flag, this allows the compilator to define a macro of your choice.

Defining the

For instance :

#ifdef DEBUG_FLAG
 printf("My error message");
#endif

2. I agree this isn't elegant either, so to make it a bit nicer :

void verbose(const char * fmt, ... )
{
va_list args;  /* Used as a pointer to the next variable argument. */
va_start( args, fmt );  /* Initialize the pointer to arguments. */

#ifdef DEBUG_FLAG
printf(fmt, &args);  
#endif
/*This isn't tested, the point is to be able to pass args to 
printf*/
}

That you could use like printf :

verbose("Error number %d\n",errorno);

3. A third solution easier, and more C++ and Unix like is to pass an argument to your program that is going to be used - as the macro earlier - to initialize a particular variable (that could be a global const).

Example : $ ./myprogram -v

if(optarg('v')) static const verbose = 1;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top