Files
school_stm32_lab/libs/pynic_log/pynic_log.h
ZZY 52097a36ee feat(school_stm32): 添加基础的 STM32F103RCT6 项目结构
- 创建了项目的基本目录结构和文件
- 添加了 CMakeLists.txt 和 Makefile 构建配置
- 创建了 main.c 文件,实现了简单的 LED 闪烁和按键检测功能
- 集成了 SEGGER RTT 库
- 添加了 .gitignore 文件,排除了不必要的生成文件
2025-06-27 23:09:57 +08:00

289 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file pythonic_log.h
* @brief 模仿python标准库logger的日志系统核心模块支持多级日志、断言和异常处理
*/
#ifndef __PYNIC_LOG_H__
#define __PYNIC_LOG_H__
#ifndef __PYNIC_NO_STDIO__
#include <stdio.h>
#include <stdlib.h>
#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__