## EasyLogger ### 源码结构 \easylogger\src\elog.c 核心功能源码 \easylogger\src\elog_async.c 核心功能异步输出模式源码 \easylogger\src\elog_buf.c 核心功能缓冲输出模式源码 \easylogger\src\elog_utils.c EasyLogger常用小工具 \easylogger\port\elog_port.c 不同平台下的EasyLogger移植接口 \easylogger\plugins\ 插件源码目录 \docs\zh\ 所有中文文档目录 \demo\non_os\stm32f10x\ stm32f10x裸机的 demo \demo\os\linux\ linux平台 demo \demo\os\windows\ windows平台 demo \demo\os\rt-thread\stm32f10x\ stm32f10x基于RT-Thread的demo(包含Flash插件demo) ### 移植 将\easylogger\(里面包含inc、src及port的那个)文件夹拷贝到项目中; 添加\easylogger\src\elog.c、\easylogger\src\elog_utils.c及\easylogger\port\elog_port.c这些文件到项目的编译路径中(elog_async.c 及 elog_buf.c 视情况选择性添加); 添加\easylogger\inc\文件夹到编译的头文件目录列表中; 移植初始化 ElogErrCode elog_port_init(void) //main() 日志输出端口 void elog_port_output(const char *log, size_t size) ```C void elog_port_output(const char *log, size_t size) { /* output to terminal */ printf("%.*s", size, log); /* output to flash */ elog_flash_write(log, size); } ``` void elog_port_output_lock(void) void elog_port_output_unlock(void) const char *elog_port_get_time(void) const char *elog_port_get_t_info(void) const char *elog_port_get_t_info(void) ### 设置参数 配置时需要修改项目中的elog_cfg.h文件,开启、关闭、修改对应的宏即可。 设置模块启用,只输出某个模块 异步输出 ### main 调用 elog_init(); /* set EasyLogger log format */ elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL); elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); /* start EasyLogger */ elog_start(); log_i("elog begin"); ### noos 使用异步 没有信号量,要在 elog_port.c异步输出要加临界区 #include "critical_section.h" /* enable asynchronous output mode */ // #define ELOG_ASYNC_OUTPUT_ENABLE /* the highest output level for async mode, other level will sync output */ #define ELOG_ASYNC_OUTPUT_LVL ELOG_LVL_ASSERT /* buffer size for asynchronous output mode */ #define ELOG_ASYNC_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 10) /* each asynchronous output's log which must end with newline sign */ #define ELOG_ASYNC_LINE_OUTPUT /* asynchronous output mode using POSIX pthread implementation */ // #define ELOG_ASYNC_OUTPUT_USING_PTHREAD ### 按子模块输出 #if !defined(LOG_TAG) #define LOG_TAG "xx" #endif #undef LOG_LVL #if defined(XX_LOG_LVL) #define LOG_LVL XX_LOG_LVL #endif ### 断言及断言钩子 EasyLogger自带的断言,可以直接用户软件,在断言表达式不成立后会输出断言信息并保持while(1),或者执行断言钩子方法,钩子方法的设定参考 elog_assert_set_hook。 void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) ```C /* EasyLogger断言钩子方法 */ static void elog_user_assert_hook(const char* ex, const char* func, size_t line) { /* 失能异步输出方式(异步输出模块自带方法) */ elog_async_enabled(false); /* 失能日志输出锁 */ elog_output_lock_enabled(false); /* 失能 EasyLogger 的 Flash 插件自带同步锁(Flash 插件自带方法) */ elog_flash_lock_enabled(false); /* 输出断言信息 */ elog_a("elog", "(%s) has assert failed at %s:%ld.\n", ex, func, line); /* 将缓冲区中所有日志保存至 Flash (Flash 插件自带方法) */ elog_flash_flush(); while(1); } ``` ### 使能日志 ### 过滤日志 void elog_set_filter_lvl(uint8_t level) void elog_set_filter_tag(const char *tag) 默认过滤标签为空字符串(""),即不过滤。 当前输出日志的标签会与过滤标签做字符串匹配,日志的标签包含过滤标签,则该输出该日志。 void elog_set_filter_kw(const char *keyword) void elog_set_filter(uint8_t level, const char *tag, const char *keyword) void elog_set_filter_tag_lvl(const char *tag, uint8_t level); ### 缓冲日志 void elog_buf_enabled(bool enabled) void elog_flush(void) 在判断出错前 ,或执行下个重要动作前执行 ### 异步shuchu void elog_async_enabled(bool enabled) size_t elog_async_get_log(char *log, size_t size) size_t elog_async_get_line_log(char *log, size_t size) elog_port.c文件 加critical_section.h elog_async_output_notice() 引入临界区 ```C void elog_async_output_notice(void) { int descriptor; descriptor=critical_section_enter(); flag_output++; critical_section_exit(descriptor); } ``` elog_async_output 预留的接口,外部实现 ```C void elog_async_output(uint8_t level, const char *log, size_t size) { /* this function must be implement by user when ELOG_ASYNC_OUTPUT_USING_PTHREAD is not defined */ extern void elog_async_output_notice(void); ``` 添加函数 void async_output(void); 头文件 elog.h 实体添加到 elog_port.c, 其他文件就不需要修改了 思路就是,通过进入临界区,判断输出日志窗口的状态。决定是否输出日志。 在main 函数, while底部调用 ```C void async_output(void){ size_t get_log_size=0; int descriptor; static char poll_get_buf[ELOG_LINE_BUF_SIZE]; descriptor=critical_section_enter(); if(descriptor<0){ return; } if(flag_output==0 || rs485_isbusy(&rs485_menu) || menu_get_state(&menu)){ critical_section_exit(descriptor); return; } flag_output--; critical_section_exit(descriptor); #ifdef ELOG_ASYNC_LINE_OUTPUT get_log_size = elog_async_get_line_log(poll_get_buf,ELOG_LINE_BUF_SIZE); #else get_log_size = elog_async_get_log(poll_get_buf, ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE); #endif if(get_log_size){ elog_port_output(poll_get_buf,get_log_size); } } ``` ### ITM通道 ITM_SendChar( ) core_cm4.c 里函数 #### 临界区代码 ```C #ifndef CRITICAL_SECTION_H_ #define CRITICAL_SECTION_H_ #include #include struct critical_section { uint32_t flag; uint8_t con; }; int critical_section_enter(void); void critical_section_exit(int descriptor); #endif ``` ```C #include "critical_section.h" #include "stm32f4xx.h" static struct critical_section cs={ .flag=0, .con=0 }; /** * @brief 进入临界区 * * @return int 成功:临界区描述符 失败:负值 */ int critical_section_enter(void) { int tmp; if(((cs.flag>>cs.con)&1)!=0){ return -2; } if(cs.flag==0){ __disable_irq(); } cs.flag|=(uint32_t)1<=32){ return; } cs.flag&=~((uint32_t)1<