#ifndef __SMCC_LOG_H__ #define __SMCC_LOG_H__ #include "../std/rt_api_def.h" #include "color.h" typedef enum log_level { LOG_LEVEL_NOTSET = 0, LOG_LEVEL_DEBUG = 1 << 0, LOG_LEVEL_INFO = 1 << 1, LOG_LEVEL_WARN = 1 << 2, LOG_LEVEL_ERROR = 1 << 3, LOG_LEVEL_FATAL = 1 << 4, LOG_LEVEL_TRACE = 1 << 5, LOG_LEVEL_ALL = 0xFF, } log_level_t; typedef void (*log_handler)( log_level_t level, const char* module, const char* file, int line, const char* message ); #ifndef LOGGER_MAX_BUF_SIZE #define LOGGER_MAX_BUF_SIZE 256 #endif typedef struct logger { const char* name; log_level_t level; log_handler handler; char buf[LOGGER_MAX_BUF_SIZE]; } logger_t; logger_t* log_get(const char* name); void log_set_level(logger_t* logger, log_level_t level); void log_set_handler(logger_t* logger, log_handler handler); #ifndef LOG_MAX_MAROC_BUF_SIZE #define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE #endif #define _LOG(_level_, _msg_, ...) \ do { \ logger_t* _logger = log_get(NULL); \ if (_logger && _logger->handler && (_logger->level & (_level_))) { \ rt.snprintf(_logger->buf, sizeof(_logger->buf), (_msg_), ##__VA_ARGS__); \ _logger->handler((_level_), _logger->name, __FILE__, __LINE__, _logger->buf); \ } \ } while(0) #define LOG_NOTSET(...) _LOG(LOG_LEVEL_NOTSET, __VA_ARGS__) #define LOG_DEBUG(...) _LOG(LOG_LEVEL_DEBUG, __VA_ARGS__) #define LOG_INFO(...) _LOG(LOG_LEVEL_INFO, __VA_ARGS__) #define LOG_WARN(...) _LOG(LOG_LEVEL_WARN, __VA_ARGS__) #define LOG_ERROR(...) _LOG(LOG_LEVEL_ERROR, __VA_ARGS__) #define LOG_FATAL(...) _LOG(LOG_LEVEL_FATAL, __VA_ARGS__) #define LOG_TRACE(...) _LOG(LOG_LEVEL_TRACE, __VA_ARGS__) #define _Assert(cond, ...) \ do { \ if (!(cond)) { \ LOG_FATAL(__VA_ARGS__); \ } \ } while (0) #define AssertFmt(cond, format, ...) _Assert(cond, "Assertion Failure: " format, ## __VA_ARGS__) #define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) #define Assert(cond) AssertFmt(cond, "cond is `" SMCC_STR(cond) "`") #define Panic(...) PanicFmt(__VA_ARGS__) #define TODO() PanicFmt("TODO please implement me") #endif