Online Book Reader

Home Category

Professional C__ - Marc Gregoire [455]

By Root 1069 0
specify a log level or error level. You can log nonerror conditions under a log level that is less severe than “error.” For example, you might want to log significant state changes in your application, or startup and shutdown of the program. You also might consider giving your users a way to adjust the log level of your program at run time so that they can customize the amount of logging that occurs.

Debug Traces

When debugging complicated problems, public error messages generally do not contain enough information. You often need a complete trace of the code path taken, or values of variables before the bug showed up. In addition to basic messages, it’s sometimes helpful to include the following information in debug traces:

The thread ID, if it’s a multithreaded program

The name of the function that generates the trace

The name of the source file in which the code that generates the trace lives

You can add this tracing to your program through a special debug mode, or via a ring buffer. Both of these methods are explained in detail in the next sections.

Debug Mode

The first technique to add debug traces is to provide a debug mode for your program. In debug mode, the program writes trace output to standard error or to a file, and perhaps does extra checking during execution. There are several ways to add a debug mode to your program.

Compile-Time Debug Mode

You can use preprocessor #ifdefs to selectively compile the debug code into your program. The advantage of this method is that your debug code is not compiled into the “release” binary, and so does not increase its size. The disadvantages are that there is no way to enable debugging at a customer site for testing or following the discovery of a bug.

The rest of this section shows an example of a simple program instrumented with a compile-time debug mode. This program doesn’t do anything useful: It is only for demonstrating the technique.

In order to generate a debug version of this program, it should be compiled with the symbol DEBUG_MODE defined. Your compiler should allow you to define symbols during compilation; consult your compiler’s documentation for details. For example, GCC allows you to specify -Dsymbol through the command-line; and Microsoft VC++ allows you to specify the symbols through the Visual Studio IDE, or if you use the VC++ command-line, /D symbol.

This example uses the C++11 variadic function template feature, which is discussed in Chapter 20. It also uses __func__, defined by the C++ standard, which is a function-local predefined variable with a definition similar to:

static const char __func__[] = "function-name";

If your compiler doesn’t support this standard __func__ yet, you should check its documentation. Maybe it supports __FUNCTION__ instead, or something similar.

The code first defines a Logger class with a static public log() method. This class is only defined when the DEBUG_MODE symbol is defined. It also defines a helper macro to make it easy to log something. Logging something in this program should be done using this macro, because it will automatically remove all logging code when DEBUG_MODE is not defined. How exactly the macro is working is explained after the code.

The log file is opened, flushed and closed on each call to log(). This might lower performance a little bit; however, it does guarantee correct logging, which is more important.

#ifdef DEBUG_MODE

class Logger

{

public:

template

static void log(const Args&... args)

{

ofstream ofs(msDebugFileName, ios_base::app);

if (ofs.fail()) {

cerr << "Unable to open debug file!" << endl;

return;

}

logHelper(ofs, args...);

ofs << endl;

}

protected:

template

static void logHelper(ofstream& ofs, const T1& t1)

{

ofs << t1;

}

template

static void logHelper(ofstream& ofs, const T1& t1, const Tn&... args)

{

ofs << t1;

logHelper(ofs, args...);

}

static const char* msDebugFileName;

};

const char* Logger::msDebugFileName = "debugfile.out";

#define log(...) Logger::log(__func__, "():

Return Main Page Previous Page Next Page

®Online Book Reader