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

Interested in new blog posts and bonus content? Sign up for my newsletter.

© 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.