不含stm32 底层的代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MyStm32Code/DOC/14_EasyLogger.md

254 lines
7.2 KiB

2 years ago
## 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 <stdint.h>
#include <stdlib.h>
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<<cs.con;
tmp=cs.con++;
cs.con&=0x1f;
return tmp;
}
/**
* @brief 退出临界区
*
* @param descriptor 临界区描述符
*/
void critical_section_exit(int descriptor)
{
if(descriptor>=32){
return;
}
cs.flag&=~((uint32_t)1<<descriptor);
if(cs.flag==0){
__enable_irq();
}
}
```