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.
254 lines
7.2 KiB
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
```
|