Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Smart debug logging in C++.NET

0.00/5 (No votes)
27 Nov 2002 1  
A smart logger that makes use of the new predefined VC++.NET macros.

Overview

Logging debug information from your code is a great way to find the problems in your application; this is specially usefull when the software is running on some customer's machine on the other side of the earth and you can not be there to investigate the particular conditions in which the application is crashing. The easy scenario described by a customer would sound like: "I choosed the Print preview option from the File menu and the application crashed"; if you can re-produce the bug on your machine, life is not that bad. What if the application is crashing or malfunctioning (apparently) random? How about a process that runs in background (like a Win service)? All you'll hear from the customer will be that he rebooted the machine and after a few minutes a message box showed saying something like "Access violation" or so...

Problem

The logs should look like this:

10/11/2002 15:25:28 CFooClass::FooMethod: 
    x is greater then zero; x = 5

Besides the string that depends on your application logic ("x is greater the zero; x = 5"), the log contains information about when (10/11/2002 15:25:28) and where (CFooClass::FooMethod) the log was made. The log can also contain the file and the line number where it was made:

10/11/2002 15:25:28 File: "C:\Adi\.NET\test1\test1.cpp"; 
    CFooClass::FooMethod; Line: 16: x is greater the zero; x = 5

The time stamp can be easily automated; automating the log of the other information requires the use of some predefined macros.

Solution

__FILE__ and __LINE__ are ANSI predefined macros (which Microsoft's compiler implements as well); this macros are replaced with the file name and the line number where these appear in source file. Besides these, Visual C++ 7.0 compiler introduces some extra predefined macros.

  • __FUNCDNAME__ returns the decorated name of the enclosing function (the C++ mangled function name)
  • __FUNCSIG__ is replaced with the signature of the enclosing function.
  • __FUNCTION__ is replaced with name of the enclosing function.

Note: These macros can only be used within a function. The function name includes class and namespace. Using these macros, we can automate the output of the required information.

The class CSmartLogger is similar to the basic_ostream from STL. The operator << is defined for most of the standard C++ types. A purpose of this class was to be used in the following way:

CSmartLogger smartlogger;

void CFooClass::FooMethod(int x)
{
    if (x > 0)
        smartlog << "x is greater the zero; x = " << x;
    else
        smartlog << "x is NOT greater the zero; x = " << x;
}

and the result to be:

10/11/2002 15:25:28 File: "C:\Adi\.NET\test1\test1.cpp"; 
    CFooClass::FooMethod; Line: 16: x is greater the zero; x = 5

As you can see, the "header" of a log can not be written when every << operator is used (using two or more operators would multiply the header of the log); even more we can not use the code that runs in << operator because we are using macros that depend on the source file and line number where they appear. Instead we can define another macro which will be inlined by the preprocessor:

extern CSmartLog __smartlog;
#define smartlog __smartlog.WriteFlags(__FILE__, 
                __LINE__, __FUNCTION__, __FUNCSIG__)

The problem with this solution is that using smartlog would log the header information, even if the intension was to set a property of class CSmartLoger; for this purpose you should use __smartlog.

To make the log class more customized, we use another class that contains the flag for the information to be logged

class CLogFlags
{
public:
    CLogFlags();

    // global flag for logs

    // when set to false, no logs are made

    bool m_bGlobalFlag;

    // when true, logs the name of the file from where the logging is made

    bool m_bFileFlag;

    // when true, logs the line number from where the logging is made

    bool m_bLineFlag;

    // when true, logs the name of the function name

    bool m_bFunctionFlag;

    // when true, logs the function, including name and its signature

    // when true, m_bFunctionFlag is ignored

    bool m_bFunctionSignFlag;

    // when true, logs the time stamp

    bool m_bTimestampFlag;
};

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here