/** * @file pythonic_log.h * @brief 模仿python标准库logger的日志系统核心模块(支持多级日志、断言和异常处理) */ #ifndef __PYNIC_LOG_H__ #define __PYNIC_LOG_H__ #ifndef __PYNIC_NO_STDIO__ #include #include #ifndef _pynic_logout_printf #define _pynic_logout_printf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #endif #ifndef _pynic_snprintf #define _pynic_snprintf snprintf #endif #ifndef _pynic_exit #define _pynic_exit exit #endif #endif #ifndef __PYNIC_NO_COLOR__ #include "pynic_color.h" #else #ifndef __PYNIC_LOG_NO_COLOR__ #define __PYNIC_LOG_NO_COLOR__ #endif #endif #ifndef PYNIC_LOGGER_MAX_BUF_SIZE #define PYNIC_LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸 #endif #ifndef NULL #define NULL ((void *)0) #endif // #define __PYNIC_LOG_IMPLIMENT__ #ifndef _pynic_exit #warning _pynic_exit not defined, it will make some exit not triggered #endif #ifndef _pynic_logout_printf #error _pynic_logout_printf not defined so log will not work #endif #ifndef _pynic_snprintf #error _pynic_logout_printf not defined so log will not work #endif #define _PYNIC_STR(str) #str #define PYNIC_STR(str) _PYNIC_STR(str) /** * @brief 日志级别枚举 * * 定义日志系统的输出级别和组合标志位 */ 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; /** * @brief 日志处理回调函数类型 * @param level 日志级别 * @param module 模块名称(可为NULL) * @param file 源文件名 * @param line 代码行号 * @param message 格式化后的日志消息 * @todo 待实现模块名称,输入的模块名称,都将被忽略 */ typedef void (*pynic_log_handler)( log_level_t level, const char* module, const char* file, int line, const char* message ); /** * @brief 日志器实例结构体 * * 每个日志器实例维护独立的配置和缓冲区 */ typedef struct logger { const char* name; ///< 日志器名称(用于模块区分) log_level_t level; ///< 当前设置的日志级别 pynic_log_handler handler; ///< 日志处理回调函数 char buf[PYNIC_LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区 } logger_t; /** * @brief 初始化日志实例 其余参数设置为默认值 * @param[in] logger 日志器实例指针 * @param[in] name 日志器名称(NULL表示获取默认日志器名称) */ void init_logger(logger_t* logger, const char* name); /** * @brief 初始化日志实例 * @param[in] logger 日志器实例指针 * @param[in] name 日志器名称(NULL表示获取默认日志器名称) * @param[in] handler 日志处理回调函数 */ void init_logger_ex(logger_t* logger, const char* name, pynic_log_handler hander); // TODO log_set(); 暂未实现 日志注册 /** * @brief 获取或创建日志器实例 * @param[in] name 日志器名称(NULL表示获取默认日志器) * @return 日志器实例指针 * @warning 若没有找到相应日志器则会返回根日志器 */ logger_t* log_get(const char* name); /** * @brief 设置日志级别 * @param[in] logger 目标日志器实例 * @param[in] level 要设置的日志级别(可组合多个级别) */ void log_set_level(logger_t* logger, log_level_t level); /** * @brief 设置自定义日志处理器 * @param[in] logger 目标日志器实例 * @param[in] handler 自定义处理函数(NULL恢复默认处理) */ void log_set_handler(logger_t* logger, pynic_log_handler handler); #ifndef LOG_MAX_MAROC_BUF_SIZE #define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE ///< 宏展开缓冲区尺寸 #endif /** * @def _LOG * @brief 内部日志宏(供其他日志宏调用) * @param _module_ 模块实例(NULL表示使用默认日志器) * @param _level_ 日志级别 * @param _msg_ 格式字符串 * @param ... 可变参数列表 */ #define _LOG(_module_, _level_, _msg_, ...) \ do { \ logger_t* _logger; \ if (_module_ == NULL) _logger = log_get(NULL); \ else _logger = _module_; \ if (_logger && _logger->handler && (_logger->level & (_level_))) { \ _pynic_snprintf(_logger->buf, sizeof(_logger->buf), (_msg_), ##__VA_ARGS__); \ _logger->handler((_level_), _logger->name, __FILE__, __LINE__, _logger->buf); \ } \ } while(0) /// @name 模块日志宏 /// @{ #define MLOG_NOTSET(module, ...) _LOG(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 #define MLOG_DEBUG( module, ...) _LOG(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别) #define MLOG_INFO( module, ...) _LOG(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) #define MLOG_WARN( module, ...) _LOG(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) #define MLOG_ERROR( module, ...) _LOG(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) #define MLOG_FATAL( module, ...) _LOG(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) #define MLOG_TRACE( module, ...) _LOG(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) /// @} /// @name 快捷日志宏 /// @{ #define LOG_NOTSET(...) _LOG(NULL, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 #define LOG_DEBUG(...) _LOG(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别) #define LOG_INFO(...) _LOG(NULL, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) #define LOG_WARN(...) _LOG(NULL, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) #define LOG_ERROR(...) _LOG(NULL, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) #define LOG_FATAL(...) _LOG(NULL, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) #define LOG_TRACE(...) _LOG(NULL, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) /// @} /** * @def _Assert * @brief 断言检查内部宏 * @param cond 检查条件表达式 * @param ... 错误信息参数(格式字符串+参数) */ #define _Assert(cond, ...) \ do { \ if (!(cond)) { \ LOG_FATAL(__VA_ARGS__); \ } \ } while (0) /// @name 断言工具宏 /// @{ #define AssertFmt(cond, format, ...) _Assert(cond, "Assertion Failure: " format, ## __VA_ARGS__) ///< 带格式的断言检查 #define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) ///< 立即触发致命错误 #ifndef Assert #define Assert(cond) AssertFmt(cond, "cond is `" PYNIC_STR(cond) "`") ///< 基础断言检查 #endif #define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息) #define TODO() PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误) /// @} static inline const char* pynic_level_str(log_level_t level) { const char* level_str; switch (level) { case LOG_LEVEL_DEBUG: level_str = "DEBUG"; break; case LOG_LEVEL_INFO: level_str = "INFO "; break; case LOG_LEVEL_WARN: level_str = "WARN "; break; case LOG_LEVEL_ERROR: level_str = "ERROR"; break; case LOG_LEVEL_FATAL: level_str = "FATAL"; break; case LOG_LEVEL_TRACE: level_str = "TRACE"; break; default: level_str = "NOTSET"; break; } return level_str; } #ifdef __PYNIC_TERMINAL_COLOR_H__ static inline const char* pynic_level_color(log_level_t level) { const char* color_code = ANSI_NONE; switch (level) { case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break; case LOG_LEVEL_INFO: color_code = ANSI_FG_GREEN; break; case LOG_LEVEL_TRACE: color_code = ANSI_FG_BLUE; break; case LOG_LEVEL_WARN: color_code = ANSI_FG_YELLOW; break; case LOG_LEVEL_ERROR: color_code = ANSI_FG_RED; break; case LOG_LEVEL_FATAL: color_code = ANSI_FG_RED ANSI_UNDERLINED; break; // 增强对比度 default: color_code = ANSI_NONE; } return color_code; } #endif #ifdef __PYNIC_LOG_IMPLIMENT__ static void __pynic_log_default_handler(log_level_t level, const char* module, const char* file, int line, const char* message) { const char* level_str = pynic_level_str(level); /// @note: 定义 __PYNIC_LOG_NO_COLOR__ 会取消颜色输出 #ifndef __PYNIC_LOG_NO_COLOR__ _pynic_logout_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n", pynic_level_color(level), level_str, module, file, line, message); #else _pynic_logout_printf("[%s] %s:%d | %s: %s\n", level_str, file, line, module, message); #endif if (level & LOG_LEVEL_FATAL) { _pynic_exit(-LOG_LEVEL_FATAL); } } static logger_t __pynic_root_logger = { .name = "root", .level = LOG_LEVEL_ALL, .handler = __pynic_log_default_handler, }; void init_logger(logger_t* logger, const char* name) { init_logger_ex(logger, name, NULL); } void init_logger_ex(logger_t* logger, const char* name, pynic_log_handler hander) { logger->name = name; logger->handler = hander ? hander : __pynic_log_default_handler; log_set_level(logger, LOG_LEVEL_ALL); } logger_t* log_get(const char* name) { if (name == NULL) return &__pynic_root_logger; return &__pynic_root_logger; } void log_set_level(logger_t* logger, log_level_t level) { if (logger) logger->level = level; else __pynic_root_logger.level = level; } void log_set_handler(logger_t* logger, pynic_log_handler handler) { if (logger) logger->handler = handler; else __pynic_root_logger.handler = handler; } #endif #endif // __PYNIC_LOG_H__