0

I'm setting up a trace facility in a large C application. I'll have multiple levels of tracing info that will get emitted using calls to a function that does syslog() emissions.

Any ideas on how I could build a macro that would wrap the test to invoke the function based on the trace level in effect? trace level is an integer bitflag.

Each higher level would incorporate each lower levels trace message type. ie: low/med/high...with high set, it would also emit med/low message types as well.

So that macro would have to do a bitwise OR to see if the current trace setting in effect incorporate the trace directive at each successive trace statement.

ideas??

user3053087
  • 87
  • 1
  • 7
  • How about showing an example usage? You can just use a macro that does nothing initially, see http://stackoverflow.com/questions/1306611/how-do-i-implement-no-op-macro-or-template-in-c – amdn Mar 22 '14 at 18:20

1 Answers1

3

Here is an idea for a general scheme:

File log.h:

#ifndef LOG_H
#define LOG_H

#include <stdio.h>

typedef enum
{
    LOG_LEVEL_ERROR,
    LOG_LEVEL_WARN ,
    LOG_LEVEL_INFO ,
    LOG_LEVEL_DEBUG,
}
log_level_e;

extern log_level_e log_level;

#define LOG(LEVEL,...)                          \
        do                                      \
        {                                       \
            if (log_level >= LOG_LEVEL_##LEVEL) \
                printf(__VA_ARGS__);            \
        }                                       \
        while (0)

#endif

File log.c:

#include <log.h>

log_level_e log_level = LOG_LEVEL_WARN; // for example

Any other source file:

#include <log.h>

void func() // for example
{
    LOG(ERROR,"Error: %d %s\n",1,"ab"); // will be printed
    LOG(WARN ,"Warn:  %d %s\n",2,"cd"); // will be printed
    LOG(INFO ,"Info:  %d %s\n",3,"ef"); // will not be printed
    LOG(DEBUG,"Debug: %d %s\n",4,"gh"); // will not be printed
}

If you want to have different logging-levels for different modules in your code, then you can use this:

typedef enum
{
    LOG_MODULE_X, // for example
    LOG_MODULE_Y, // for example
    ...
    LOG_NUM_OF_MODULES
}
log_module_e;

extern log_level_e log_level[LOG_NUM_OF_MODULES];

#define LOG(LEVEL,MODULE,...)                                        \
        do                                                           \
        {                                                            \
            if (log_level[LOG_MODULE_##MODULE] >= LOG_LEVEL_##LEVEL) \
                printf(__VA_ARGS__);                                 \
        }                                                            \
        while (0)

Please note that in a multi-threaded application, you will have to replace each call to printf with a call to a function that sends the arguments in a message to a designated thread, which will perform the calls to printf in a sequential manner (this is true regardless of whether or not you use a logging system).

Here is how you can prepare and send each message:

void send_msg_to_log_thread(const char* data,...)
{
    char msg[MAX_SIZE_OF_LOG_MSG];
    va_list args;
    va_start(args,data);
    vsnprintf(msg,MAX_SIZE_OF_LOG_MSG,data,args);
    va_end(args);
    // Now, send the 'msg' buffer to the designated thread
}
barak manos
  • 29,648
  • 10
  • 62
  • 114