C++17 In Detail

12 May 2012

Logger update

See my new website at cppstories.com

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 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__); \
 #define LOG(msg, ...) { }
 #define LOG_ERROR(msg, ...) { }

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);
 strcat_s(strBuf, "\n");

        // display the results:

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++

If you want to get additional C++ resources, exlusive articles, early access content, private Discord server and weekly curated news, check out my Patreon website: (see all benefits):

© 2017, Bartlomiej Filipek, Blogger platform
Disclaimer: Any opinions expressed herein are in no way representative of those of my employers. All data and information provided on this site is for informational purposes only. I try to write complete and accurate articles, but the web-site will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use.
This site contains ads or referral links, which provide me with a commission. Thank you for your understanding.