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
}