2

Is there a way to make the log-level checking in my LOGGING-macro (shown below) to happen during compile-time? It should be possible as it is already known during compile time whether the condition (if (pLogLevel <= LOG_LEVEL)) is true or false. Here is an example of how the macro could be used:

LOGGING(LOG_DEBUG, "FALSE - Wrong Marker\n");

Originally I thought that #ifdirectives within a #define could help me, but this article showed me that this would not be possible. This is the source code to my problem:

#ifndef __LOGGING_H__
#define __LOGGING_H__ 1

#include <time.h>

#define LOG_EMERG    0   
#define LOG_ALERT    1   
#define LOG_CRIT     2   
#define LOG_ERROR    3   
#define LOG_WARN     4   
#define LOG_NOTICE   5   
#define LOG_INFO     6   
#define LOG_DEBUG    7   
#define LOG_NONE     8   

/* set the global logging level here */
#define LOG_LEVEL LOG_INFO

void print_timestamp(void);

#if LOG_LEVEL == LOG_DEBUG
#define _LOG_PREAMBLE                                       \   
        fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
#else
#define _LOG_PREAMBLE                                       \   
        print_timestamp();
#endif

#if LOG_LEVEL == LOG_EMERG
#define _LOG_LEVEL fprintf(stdout, "EMERG "); 
#elif LOG_LEVEL == LOG_ALERT
#define _LOG_LEVEL fprintf(stdout, "ALERT "); 
#elif LOG_LEVEL == LOG_CRIT
#define _LOG_LEVEL fprintf(stdout, "CRIT "); 
#elif LOG_LEVEL == LOG_ERROR
#define _LOG_LEVEL fprintf(stdout, "ERROR "); 
#elif LOG_LEVEL == LOG_WARN
#define _LOG_LEVEL fprintf(stdout, "WARN "); 
#elif LOG_LEVEL == LOG_NOTICE
#define _LOG_LEVEL fprintf(stdout, "NOTICE "); 
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "INFO "); 
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "DEBUG "); 
#else
#define _LOG_LEVEL
#endif

#define LOGGING(pLogLevel, ...)                               \   
    /* change this to compile time conditional if possible */ \   
    if (pLogLevel <= LOG_LEVEL)                               \   
    {                                                         \   
        _LOG_PREAMBLE                                         \   
        _LOG_LEVEL                                            \   
        fprintf(stdout, ##__VA_ARGS__);                       \   
    }   

#endif /* __LOGGING_H__ */
Community
  • 1
  • 1
dubbaluga
  • 2,223
  • 5
  • 29
  • 38
  • Chances are very good a compiler will eliminate the code of your LOGGING() macro when the condition is false when you turn on optimization , and also it will eliminate the if() conditional check when the condition is true - leaving only the body of the if() left in the code. I'd file it as a bug to the compiler if it didn't. – nos Aug 31 '12 at 22:34
  • This is the job of the code generator. It can see that the if() statement is always false and knows to eliminate the code. You don't have to help, just make sure the optimizer is enabled. – Hans Passant Aug 31 '12 at 22:46
  • Thank you the two of you. These are useful comments. It definitely makes sense that the compiler or optimizer enables/disables code in conditionals that are always true or false, respectively. – dubbaluga Sep 06 '12 at 21:58

2 Answers2

2

One approach would be to combine the log level into the logging macro.

This would create a set of macros that would be turned on or off depending on the log level.

You would use these macros and they would appear or not depending on the log level at the time of the compile. So they would be used like the following.

LOGGING_LEVEL_DEBUG("a Debug log.");
//.... some code
LOGGING_LEVEL_EMERG("a Emerge log.");

So the macros definitions would look something like the following:

    #define LOG_EMERG    0   
    #define LOG_ALERT    1   
    #define LOG_CRIT     2   
    #define LOG_ERROR    3   
    #define LOG_WARN     4   
    #define LOG_NOTICE   5   
    #define LOG_INFO     6   
    #define LOG_DEBUG    7   
    #define LOG_NONE     8   

    /* set the global logging level here */
    #define LOG_LEVEL LOG_INFO

    void print_timestamp(void);

    #if LOG_LEVEL >= LOG_DEBUG
    #define _LOG_PREAMBLE                                       \
            fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
    #else
    #define _LOG_PREAMBLE                                       \
            print_timestamp();
    #endif

    #if LOG_LEVEL >= LOG_EMERG
        #define LOGGING_LEVEL_EMERG(...) \
            {                                                         \
                _LOG_PREAMBLE                                         \
                fprintf(stdout, "EMERG ");                                           \
                fprintf(stdout, ##__VA_ARGS__);                       \
            }   

        #else
        #define LOGGING_LEVEL_EMERG(...)
        #endif

        #if LOG_LEVEL >= LOG_ALERT
        #define LOGGING_LEVEL_ALERT(...) \
            {                                                         \
                _LOG_PREAMBLE                                         \
                fprintf(stdout, "ALERT ");                                           \
                fprintf(stdout, ##__VA_ARGS__);                       \
            }   

        #else
        #define LOGGING_LEVEL_ALERT(...)
        #endif
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
0

You could define the macros themselves conditionally:

#if LOG_LEVEL > 0
#  define LOG(...) printf(__VA_ARGS__)
#else
#  define LOG(...)
#endif

#if LOG_LEVEL > 1
// and so forth
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084