Partners: KDAB Whole Tomato Software CppDepend

12 May 2012

Logger update

Having a good logger might be really beneficial when developing and monitoring apps. Simple loggers might just use printf function, but what if we want to upgrade it a bit, and for instance see the log inside the Output windows in Visual Studio? In this post I'd like to present some useful code that should improve your loggers.

Last Update: 23rd July 2016

Here's a declaration of the logger:

// decide which one you want to use
//#define UTILS_LOG_WITH_PRINTF
#define UTILS_LOG_WITH_OUTPUT_DBG_STRING

#ifdef UTILS_LOG_WITH_PRINTF
 #define LOG(msg, ...) { \
            printf(msg, __VA_ARGS__); \
            printf("\n"); \
        }
 #define LOG_ERROR(msg, ...) { \
            printf("ERR in %s at line %d: ", __FUNCTION__, __LINE__); \
            printf(msg, __VA_ARGS__); \
            printf("\n"); \
        }
#elif defined (UTILS_LOG_WITH_OUTPUT_DBG_STRING) && defined(WIN32)
 #define LOG(msg, ...) { \
            winOutDebugString(0, 0, 0, 0, msg, __VA_ARGS__); \
        } 
 #define LOG_ERROR(msg, ...) { \
            winOutDebugString(__FUNCTION__, __FILE__, __LINE__, \
                              "ERR", msg, __VA_ARGS__); \
        }
#else
 #define LOG(msg, ...) { }
 #define LOG_ERROR(msg, ...) { }
#endif

The above code, heavily macro based, let's you decide what output function it will internally use. You can use normal printf or OutputDebugString . The latter function let's write to Debug stream, so you could see the logs in Visual Studio Output Window, or even DebugView application.

The logger also uses the following predefined macros

  • __VA_ARGS__ - variable args for macro
  • __FUNCTION__ - function name where the log macro is invoked
  • __FILE__ - file name where the log macro is invoked
  • __LINE__ - line number of the file

Unfortunately OutputDebugString does not have printf functionality, so we need to create a helper function that will compose a string from a variable number of parameters.

Below there is some code that illustrate how to create such helper function:

#ifdef WIN32
void winOutDebugString(const char *func, const char * file, int line, 
                       const char *msg, const char *userMsg, ...)
{
 static char strBuf[512];
 static char strTemp[512];

 strBuf[0] = '\0';

 // handle "msg" with varying number of params:
 va_list  ap;

 if (userMsg == NULL) return; 

 strBuf[0] = '\0';
 va_start(ap, userMsg); 
 vsprintf_s(strBuf, userMsg, ap);
 va_end(ap);
 strcat_s(strBuf, "\n");

        // display the results:
 OutputDebugString(strBuf);
}
#endif

There's even more to that, you can read in my debugging tips post how to format the log message so that you can easily jump betwenn the log message and the source code.

Read about useful predefined macros for logging in my previous post: __FUNCTION__ macro in Visual C++

Get my free ebook about C++17!

More than 50 pages about the new Language Standard.

C++17 in detail, by Bartlomiej Filipek

© 2017, Bartlomiej Filipek, Blogger platform
Any opinions expressed herein are in no way representative of those of my employers.
This site contains ads or referral links, which provide me with a commission. Thank you for your understanding.