views:

546

answers:

7

So I have a C++ program, that normally when it executes writes out things to a log file. This is done using an fstream. However, now I want to include functionality to turn the logging off. Essentially, my code looks like this:

bool isLogging;
fstream* logFilePtr;

throughout my code, there are a bunch of statements like:

(*logFilePtr) << "    Kernel call time in seconds: " << kTime << endl;
...

Now, if the "isLogging" is true, I don't want these to print. I could just go surround them with a bunch of if statements, but I'd prefer something cleaner than that. I thought there was some way to take a C++ stream and redirect it to point to "nothing" so that when the << operator is used, nothing will print.

Does anyone know how to redirect the stream, or have any other ideas on how to handle this in an elegant way?

Thanks, Colin

+5  A: 

You could wrap it up in a class.

class Log {
  Log (fstream &s) : stream(s), enabled(false) { }
  void Enable () { enabled = true; }
  void Disable () { enabled = false; }

  template<class T>
  Log &operator<< (T const& rhs) {
    if (enabled) stream << rhs;
    return *this;
  }

private:
  fstream &stream;
  bool enabled;
};

this isn't tested .. but the basic idea should be there.

eduffy
A: 

platform? if you are under unix you can write the file to /dev/null

klez
Under windows you could use nul for the same effect
Todd Gardner
A: 

I use POCO library's logging feature. It supports configuring channels - console, file, both. Configuring format of output and logging levels (trace, debug, error etc). I then surround the logging functionality with functions such as

inline void logError(const std::string & str)
{
#ifdef COMPILE_ERROR_LOGGING
   g_pMyPocoLogger->error(str);
#endif
}

You can choose not to use the library but I still recommend surrounding your logging with a wrapper.

Budric
+4  A: 

Take a look at rdbuf member function. You can create a discarding stream buffer and associate it with your stream.

struct nullbuf: std::streambuf
{
    int overflow(int c) { return traits_type::not_eof(c); }
};
avakar
A: 

std::iostream doesn't allow OS-level redirection, however, you can share std::streambufs between std::iostreams:

int main() {
    // redirect stdout to stderr:
    std::streambuf * const oldstdout = std::cout.rdbuf();
    std::cout.rdbuf( std::cerr.rdbuf() );

    // test
    std::cout << "Hello ";
    std::cerr << "World" << std::endl;

    // re-set, so streambufs are properly deleted:
    std::cout.rdbuf( oldstdout );

    // test
    std::cout << "Hello ";
    std::cerr << "World" << std::endl;

    return 0;
}

This way, you can redirect logging to somewhere else (e.g. "/dev/null" :), or, if you follow avakar's answer, use nullbuf.

A: 
std::ostream& Debug(int level) {
  std::clog.clear(levell <= shown_level ? std::ios_base::goodbit: std::ios_base::badbit);
  return std::clog;
}

From comp.lang.c++.

mcandre
A: 

Under "other ideas on how to handle this":

  1. Use the state pattern to eliminate the need for the if checks around all code.
  2. Use the policy pattern (compile time strategy pattern) with a Logging policy object.
ceretullis