John
John

Reputation: 3484

How to simplify the similar macros?

It's a pity that there are a lot similar macros(both name and function) in the code below. How to simplify the similar macros?

The difference between the similar macros are the string tags, say [PROC_E] indicats it's an error message for the module named PROC while [SERVICE_E] indicats it's an error message for the module named SERVICE.

#include <stdio.h>
#include <type_traits>
#include <mutex>
#include <stdarg.h>

typedef enum 
{
    NONE,
    DEBUG,
    WARNING,
    ERROR,
}log_level_em;

class SimpleLog
{
private:
    SimpleLog() = default;
    SimpleLog(const SimpleLog&) = delete;
    SimpleLog& operator=(const SimpleLog&) = delete;
public:
    static SimpleLog& get_instance()
    {
        static SimpleLog logger;
        return logger;
    }

    void set_block_level(log_level_em level)
    {
        block_level = level;
    }

    bool block_log(log_level_em level)
    {
        return static_cast<std::underlying_type<log_level_em>::type>(level) <= \
               static_cast<std::underlying_type<log_level_em>::type>(block_level);
    }

    void log_output(log_level_em level, const char* fmt, ...)
    {
        if(block_log(level))
        {
            return;
        }

        va_list args;
        va_start(args, fmt);
        {
            std::unique_lock<std::mutex> lock{mtx};
            vprintf(fmt, args);
        }
        va_end(args);
    }

    log_level_em block_level{NONE};
    std::mutex mtx;
};

#define LOG_SET_LEVEL(lvl)                          \
do{                                                 \
    SimpleLog::get_instance().set_block_level(lvl); \
} while(false);

// Define the LOG_COMMON macro to accept variadic parameters
#define LOG_COMMON(log_level, fmt, ...)                                        \
do{                                                                            \
    SimpleLog::get_instance().log_output(log_level, "[%s] [%s:%d] " fmt "\n",  \
                             __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); \
} while(false);

// All the macros call LOG_COMMON
#define CAM_LOG_ERROR(fmt, ...)   LOG_COMMON(ERROR,   "[CAM_E] "  fmt, ##__VA_ARGS__)
#define CAM_LOG_WARNING(fmt, ...) LOG_COMMON(WARNING, "[CAM_W] " fmt, ##__VA_ARGS__)
#define CAM_LOG_DEBUG(fmt, ...)   LOG_COMMON(DEBUG,   "[CAM_D] " fmt, ##__VA_ARGS__)

#define PROC_LOG_ERROR(fmt, ...)   LOG_COMMON(ERROR,   "[PROC_E] " fmt, ##__VA_ARGS__)
#define PROC_LOG_WARNING(fmt, ...) LOG_COMMON(WARNING, "[PROC_W] " fmt, ##__VA_ARGS__)
#define PROC_LOG_DEBUG(fmt, ...)   LOG_COMMON(DEBUG,   "[PROC_D] " fmt, ##__VA_ARGS__)

#define SERVICE_LOG_ERROR(fmt, ...)   LOG_COMMON(ERROR,   "[SERVICE_E] " fmt, ##__VA_ARGS__)
#define SERVICE_LOG_WARNING(fmt, ...) LOG_COMMON(WARNING, "[SERVICE_W] " fmt, ##__VA_ARGS__)
#define SERVICE_LOG_DEBUG(fmt, ...)   LOG_COMMON(DEBUG,   "[SERVICE_D] " fmt, ##__VA_ARGS__)

int main() {
    LOG_SET_LEVEL(DEBUG);

    CAM_LOG_ERROR("the fd(%d) can't be opened!", 5);
    CAM_LOG_WARNING("this is a warning from %s !", "message processing thread");
    PROC_LOG_ERROR("this is a warning from %s !", "message processing thread");
    PROC_LOG_DEBUG("this message should not be seen");
    SERVICE_LOG_WARNING("failed to run function");
    return 0;
}

Upvotes: 0

Views: 85

Answers (0)

Related Questions