## 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();
    }
}


```