diff --git a/demo/os/linux/easylogger/inc/elog_cfg.h b/demo/os/linux/easylogger/inc/elog_cfg.h index 1bcacc0..b33265c 100644 --- a/demo/os/linux/easylogger/inc/elog_cfg.h +++ b/demo/os/linux/easylogger/inc/elog_cfg.h @@ -51,6 +51,8 @@ #define ELOG_ASYNC_OUTPUT_ENABLE /* buffer size for asynchronous output mode */ #define ELOG_ASYNC_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 100) +/* 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 diff --git a/demo/os/rt-thread/stm32f10x/components/easylogger/inc/elog_cfg.h b/demo/os/rt-thread/stm32f10x/components/easylogger/inc/elog_cfg.h index b9687fe..8c6c9c5 100644 --- a/demo/os/rt-thread/stm32f10x/components/easylogger/inc/elog_cfg.h +++ b/demo/os/rt-thread/stm32f10x/components/easylogger/inc/elog_cfg.h @@ -48,7 +48,9 @@ /* enable asynchronous output mode */ #define ELOG_ASYNC_OUTPUT_ENABLE /* buffer size for asynchronous output mode */ -#define ELOG_ASYNC_OUTPUT_BUF_SIZE ELOG_LINE_BUF_SIZE * 10 +#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 diff --git a/demo/os/rt-thread/stm32f10x/components/easylogger/port/elog_port.c b/demo/os/rt-thread/stm32f10x/components/easylogger/port/elog_port.c index 520ebdb..14022e5 100644 --- a/demo/os/rt-thread/stm32f10x/components/easylogger/port/elog_port.c +++ b/demo/os/rt-thread/stm32f10x/components/easylogger/port/elog_port.c @@ -133,7 +133,13 @@ static void async_output(void *arg) { rt_sem_take(&output_notice, RT_WAITING_FOREVER); /* polling gets and outputs the log */ while(true) { + +#ifdef ELOG_ASYNC_LINE_OUTPUT + get_log_size = elog_async_get_line_log(poll_get_buf, sizeof(poll_get_buf)); +#else get_log_size = elog_async_get_log(poll_get_buf, sizeof(poll_get_buf)); +#endif + if (get_log_size) { elog_port_output(poll_get_buf, get_log_size); } else { diff --git a/docs/zh/api/kernel.md b/docs/zh/api/kernel.md index 450c147..6b3003f 100644 --- a/docs/zh/api/kernel.md +++ b/docs/zh/api/kernel.md @@ -38,6 +38,8 @@ void elog_start(void) 5 [V] 详细(Verbose) ``` +#### 1.3.1 输出基本日志 + 所有级别的日志输出方法如下,每种级别都有一种简写方式,用户可以自行选择。 ```c @@ -100,8 +102,21 @@ void elog_start(void) #endif ``` + +#### 1.3.2 输出RAW格式日志 + +``` +void elog_raw(const char *format, ...) +``` +|参数 |描述| +|:----- |:----| +|format |样式,类似`printf`首个入参| +|... |不定参| + ### 1.4 断言 +#### 1.4.1 使用断言 + EasyLogger自带的断言,可以直接用户软件,在断言表达式不成立后会输出断言信息并保持`while(1)`,或者执行断言钩子方法,钩子方法的设定参考 [`elog_assert_set_hook`](#114-设置断言钩子方法)。 ``` @@ -112,7 +127,21 @@ EasyLogger自带的断言,可以直接用户软件,在断言表达式不成 |:----- |:----| |EXPR |表达式| -### 1.5 使能/失能日志输出 +#### 1.4.2 设置断言钩子方法 + +默认断言钩子方法为空,设置断言钩子方法后。当断言`ELOG_ASSERT(EXPR)`中的条件不满足时,会自动执行断言钩子方法。断言钩子方法定义及使用可以参考上一章节的例子。 + +```c +void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) +``` + +|参数 |描述| +|:----- |:----| +|hook |断言钩子方法| + +### 1.5 日志输出控制 + +#### 1.5.1 使能/失能日志输出 ``` void elog_set_output_enabled(bool enabled) @@ -121,13 +150,44 @@ void elog_set_output_enabled(bool enabled) |:----- |:----| |enabled |true: 使能,false: 失能| -### 1.6 获取日志使能状态 +#### 1.5.2 获取日志使能状态 ``` bool elog_get_output_enabled(void) ``` -### 1.7 设置日志格式 +#### 1.5.3 使能/失能日志输出锁 + +默认为使能状态,当系统或MCU进入异常后,需要输出异常日志时,就必须失能日志输出锁,来保证异常日志能够被正常输出。 + +``` +void elog_output_lock_enabled(bool enabled) +``` + +|参数 |描述| +|:----- |:----| +|enabled |true: 使能,false: 失能| + +例子: + +```c +/* EasyLogger断言钩子方法 */ +static void elog_user_assert_hook(const char* ex, const char* func, size_t line) { + /* 失能日志输出锁 */ + 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); +} +``` + +### 1.6 日志格式及样式 + +#### 1.6.1 设置日志格式 每种级别可对应一种日志输出格式,日志的输出内容位置顺序固定,只可定义开启或关闭某子内容。可设置的日志子内容包括:级别、标签、时间、进程信息、线程信息、文件路径、行号、方法名。 @@ -159,124 +219,117 @@ elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); ``` -### 1.8 设置过滤级别 +#### 1.6.2 使能/失能日志颜色 -默认过滤级别为5(详细),用户可以任意设置。在设置高优先级后,低优先级的日志将不会输出。例如:设置当前过滤的优先级为3(警告),则只会输出优先级别为警告、错误、断言的日志。 +日志颜色功能是将各个级别日志按照颜色进行区分,默认颜色功能是关闭的。日志的颜色修改方法详见《EasyLogger 移植说明》中的 `设置参数` 章节。 ``` -void elog_set_filter_lvl(uint8_t level) +void elog_set_text_color_enabled(bool enabled) ``` |参数 |描述| |:----- |:----| -|level |级别| +|enabled |true: 使能,false: 失能| -### 1.9 设置过滤标签 +#### 1.6.3 查找日志级别 -默认过滤标签为空字符串(`""`),即不过滤。当前输出日志的标签会与过滤标签做字符串匹配,日志的标签包含过滤标签,则该输出该日志。例如:设置过滤标签为WiFi,则系统中包含WiFi字样标签的(WiFi.Bsp、WiFi.Protocol、Setting.Wifi)日志都会被输出。 +在日志中查找该日志的级别。查找成功则返回其日志级别,查找失败则返回 -1 。 ->注:RAW格式日志不支持标签过滤 +> **注意** :使用此功能时,请务必保证所有级别的设定的日志格式里均已开启输出日志级别功能,否则会断言错误。 ``` -void elog_set_filter_tag(const char *tag) +int8_t elog_find_lvl(const char *log) ``` |参数 |描述| |:----- |:----| -|tag |标签| +|log |待查找的日志缓冲区| -### 1.10 设置过滤关键词 +#### 1.6.4 查找日志标签 -默认过滤关键词为空字符串(""),即不过滤。检索当前输出日志中是否包含该关键词,包含则允许输出。 +在日志中查找该日志的标签。查找成功则返回其日志标签及标签长度,查找失败则返回 NULL 。 -> 注:对于配置较低的MCU建议不开启关键词过滤(默认为不过滤),增加关键字过滤将会在很大程度上减低日志的输出效率。实际上当需要实时查看日志时,过滤关键词功能交给上位机做会更轻松,所以后期的跨平台日志助手开发完成后,就无需该功能。 +> **注意** :使用此功能时,首先请务必保证该级别对应的设定日志格式中,已开启输出日志标签功能,否则会断言错误。其次需保证设定日志标签中 **不能包含空格** ,否则会查询失败。 ``` -void elog_set_filter_kw(const char *keyword) +const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len) ``` |参数 |描述| |:----- |:----| -|keyword |关键词| +|log |待查找的日志缓冲区| +|lvl |待查找日志的级别| +|tag_len |查找到的标签长度| -### 1.11 设置过滤器 +### 1.7 过滤日志 -设置过滤器后,只输出符合过滤要求的日志。所有参数设置方法,可以参考上述3个章节。 +#### 1.7.1 设置过滤级别 + +默认过滤级别为5(详细),用户可以任意设置。在设置高优先级后,低优先级的日志将不会输出。例如:设置当前过滤的优先级为3(警告),则只会输出优先级别为警告、错误、断言的日志。 ``` -void elog_set_filter(uint8_t level, const char *tag, const char *keyword) +void elog_set_filter_lvl(uint8_t level) ``` |参数 |描述| |:----- |:----| |level |级别| -|tag |标签| -|keyword |关键词| -### 1.12 输出RAW格式日志 +#### 1.7.2 设置过滤标签 + +默认过滤标签为空字符串(`""`),即不过滤。当前输出日志的标签会与过滤标签做字符串匹配,日志的标签包含过滤标签,则该输出该日志。例如:设置过滤标签为WiFi,则系统中包含WiFi字样标签的(WiFi.Bsp、WiFi.Protocol、Setting.Wifi)日志都会被输出。 + +>注:RAW格式日志不支持标签过滤 ``` -void elog_raw(const char *format, ...) +void elog_set_filter_tag(const char *tag) ``` + |参数 |描述| |:----- |:----| -|format |样式,类似`printf`首个入参| -|... |不定参| +|tag |标签| -### 1.13 使能/失能日志输出锁 +#### 1.7.3 设置过滤关键词 -默认为使能状态,当系统或MCU进入异常后,需要输出异常日志时,就必须失能日志输出锁,来保证异常日志能够被正常输出。 +默认过滤关键词为空字符串(""),即不过滤。检索当前输出日志中是否包含该关键词,包含则允许输出。 + +> 注:对于配置较低的MCU建议不开启关键词过滤(默认为不过滤),增加关键字过滤将会在很大程度上减低日志的输出效率。实际上当需要实时查看日志时,过滤关键词功能交给上位机做会更轻松,所以后期的跨平台日志助手开发完成后,就无需该功能。 ``` -void elog_output_lock_enabled(bool enabled) +void elog_set_filter_kw(const char *keyword) ``` |参数 |描述| |:----- |:----| -|enabled |true: 使能,false: 失能| - -例子: - -```c -/* EasyLogger断言钩子方法 */ -static void elog_user_assert_hook(const char* ex, const char* func, size_t line) { - /* 失能日志输出锁 */ - 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); -} -``` +|keyword |关键词| -### 1.14 设置断言钩子方法 +#### 1.7.4 设置过滤器 -默认断言钩子方法为空,设置断言钩子方法后。当断言`ELOG_ASSERT(EXPR)`中的条件不满足时,会自动执行断言钩子方法。断言钩子方法定义及使用可以参考上一章节的例子。 +设置过滤器后,只输出符合过滤要求的日志。所有参数设置方法,可以参考上述3个章节。 -```c -void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) +``` +void elog_set_filter(uint8_t level, const char *tag, const char *keyword) ``` |参数 |描述| |:----- |:----| -|hook |断言钩子方法| +|level |级别| +|tag |标签| +|keyword |关键词| -### 1.15 使能/失能日志颜色 +### 1.8 缓冲输出模式 -日志颜色功能是将各个级别日志按照颜色进行区分,默认颜色功能是关闭的。日志的颜色修改方法详见《EasyLogger 移植说明》中的 `设置参数` 章节。 +#### 1.8.1 使能/失能缓冲输出模式 ``` -void elog_set_text_color_enabled(bool enabled) +void elog_buf_enabled(bool enabled) ``` - |参数 |描述| |:----- |:----| |enabled |true: 使能,false: 失能| -### 1.16 将缓冲区中的日志全部输出 + +#### 1.8.2 将缓冲区中的日志全部输出 在缓冲输出模式下,执行此方法可以将缓冲区中的日志全部输出干净。 @@ -284,16 +337,18 @@ void elog_set_text_color_enabled(bool enabled) void elog_flush(void) ``` -### 1.17 使能/失能缓冲输出模式 +### 1.9 异步输出模式 + +#### 1.9.1 使能/失能异步输出模式 ``` -void elog_buf_enabled(bool enabled) +void elog_async_enabled(bool enabled) ``` |参数 |描述| |:----- |:----| |enabled |true: 使能,false: 失能| -### 1.18 在异步输出模式下获取日志 +#### 1.9.2 在异步输出模式下获取日志 在异步输出模式下,如果用户没有启动 pthread 库,此时需要启用额外线程来实现日志的异步输出功能。使用此方法即可获取到异步输出缓冲区中的指定长度的日志。如果设定日志长度小于日志缓冲区中已存在日志长度,将只会返回已存在日志长度。 @@ -306,14 +361,18 @@ size_t elog_async_get_log(char *log, size_t size) |log |取出的日志内容| |size |待取出的日志大小| -### 1.19 使能/失能异步输出模式 +#### 1.9.3 在异步输出模式下获取行日志(以换行符结尾) +异步模式下获取行日志与 1.9.2 中的直接获取日志功能类似,只不过这里所获取到的日志内容,必须为为 **行日志** (以换行符结尾)格式,为后续的日志按行分析功能提供便利。如果设定日志长度小于日志缓冲区中已存在日志长度,将只会返回日志缓冲区中行日志的长度。如果缓冲区中不存在行日志,将不能保证返回的日志格式是行日志。 + +```C +size_t elog_async_get_line_log(char *log, size_t size) ``` -void elog_async_enabled(bool enabled) -``` + |参数 |描述| |:----- |:----| -|enabled |true: 使能,false: 失能| +|log |取出的行日志内容| +|size |待取出的行日志大小| ## 2、配置 diff --git a/docs/zh/port/kernel.md b/docs/zh/port/kernel.md index be6e5cb..1820cee 100644 --- a/docs/zh/port/kernel.md +++ b/docs/zh/port/kernel.md @@ -174,7 +174,7 @@ const char *elog_port_get_t_info(void) ### 4.9 颜色 -> **注意** :启用颜色功能需先定义 `ELOG_COLOR_ENABLE` 这个宏 +> **注意** :启用颜色功能需先定义 `ELOG_COLOR_ENABLE` 每个级别的日志均有默认颜色。如果想修改,请先查看在 `elog.c` 的头部定义的各种颜色及字体风格,这里以修改 `VERBOSE` 级别日志来举例: @@ -199,7 +199,13 @@ const char *elog_port_get_t_info(void) - 默认大小:`(ELOG_LINE_BUF_SIZE * 10)` ,不定义此宏,将会自动按照默认值设置 - 操作方法:修改`ELOG_ASYNC_OUTPUT_BUF_SIZE`宏对应值即可 -#### 4.10.2 启用 pthread 库 +#### 4.10.2 异步按行输出日志 + +由于异步输出方式内部拥有缓冲区,所以直接输出缓冲区中积累的日志时,日志移植输出方法 (`elog_port_output`) 输出的日志将不会按照 **行日志** (以换行符结尾)的格式进行输出。这使得无法在移植输出方法中完成日志的分析处理。开启此功能后,将会最大限度保证移植输出方法每次输出的日志格式都为行日志。 + +- 操作方法:开启、关闭`ELOG_ASYNC_LINE_OUTPUT`宏即可 + +#### 4.10.3 启用 pthread 库 异步输出模式默认是使用 POSIX 的 pthread 库来实现,用户的平台如果支持 pthread ,则可以开启此宏。对于一些缺少 pthread 的支持平台,可以关闭此宏,参考 `elog_async.c` 中关于日志异步输出线程的实现方式,自己动手实现此功能。 @@ -222,7 +228,7 @@ const char *elog_port_get_t_info(void) 每次使用前,务必先执行`elog_init()`方法对EasyLogger库进行初始化,保证初始化没问题后,再设置输出格式、过滤级别、断言钩子等,最后记得调用`elog_start()`方法启动EasyLogger,否则EasyLogger将不会开始工作。启动后接上终端就即可日志的输出信息,可以参考并运行这里的[日志测试函数](https://github.com/armink/EasyLogger/blob/master/demo/os/windows/main.c#L76-L88)。如果出现错误或断言,需根据提示信息检查移植配置及接口。 -下面为常见初始化方式([点击查看源码](https://github.com/armink/EasyLogger/blob/master/demo/os/windows/main.c#L44-L56)) +下面为常见初始化方式([点击查看源码](https://github.com/armink/EasyLogger/blob/master/demo/os/windows/main.c)) ```c /* close printf buffer */ setbuf(stdout, NULL); diff --git a/easylogger/inc/elog.h b/easylogger/inc/elog.h index 7b44153..85801f0 100644 --- a/easylogger/inc/elog.h +++ b/easylogger/inc/elog.h @@ -50,7 +50,7 @@ extern "C" { #define ELOG_LVL_TOTAL_NUM 6 /* EasyLogger software version number */ -#define ELOG_SW_VERSION "1.11.24" +#define ELOG_SW_VERSION "1.11.25" /* EasyLogger assert for developer. */ #ifdef ELOG_ASSERT_ENABLE @@ -129,6 +129,8 @@ void elog_output(uint8_t level, const char *tag, const char *file, const char *f void elog_output_lock_enabled(bool enabled); extern void (*elog_assert_hook)(const char* expr, const char* func, size_t line); void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)); +int8_t elog_find_lvl(const char *log); +const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len); #ifndef ELOG_OUTPUT_ENABLE @@ -193,15 +195,17 @@ void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_ #define elog_v(tag, ...) elog_verbose(tag, __VA_ARGS__) /* elog_buf.c */ -void elog_flush(void); void elog_buf_enabled(bool enabled); +void elog_flush(void); /* elog_async.c */ -size_t elog_async_get_log(char *log, size_t size); 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_utils.c */ size_t elog_strcpy(size_t cur_len, char *dst, const char *src); +size_t elog_cpyln(char *line, const char *log, size_t len); #ifdef __cplusplus } diff --git a/easylogger/inc/elog_cfg.h b/easylogger/inc/elog_cfg.h index faea605..5135627 100644 --- a/easylogger/inc/elog_cfg.h +++ b/easylogger/inc/elog_cfg.h @@ -60,6 +60,8 @@ #define ELOG_ASYNC_OUTPUT_ENABLE /* 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 diff --git a/easylogger/src/elog.c b/easylogger/src/elog.c index e405134..954095f 100644 --- a/easylogger/src/elog.c +++ b/easylogger/src/elog.c @@ -572,3 +572,79 @@ void elog_output_lock_enabled(bool enabled) { void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) { elog_assert_hook = hook; } + +/** + * find the log level + * @note make sure the log level is output on each format + * + * @param log log buffer + * + * @return log level, found failed will return -1 + */ +int8_t elog_find_lvl(const char *log) { + ELOG_ASSERT(log); + /* make sure the log level is output on each format */ + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ASSERT] & ELOG_FMT_LVL); + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ERROR] & ELOG_FMT_LVL); + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_WARN] & ELOG_FMT_LVL); + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_INFO] & ELOG_FMT_LVL); + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_DEBUG] & ELOG_FMT_LVL); + ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_VERBOSE] & ELOG_FMT_LVL); + +#ifdef ELOG_COLOR_ENABLE + uint8_t i; + size_t csi_start_len = strlen(CSI_START); + for(i = 0; i < ELOG_LVL_TOTAL_NUM; i ++) { + if (!strncmp(color_output_info[i], log + csi_start_len, strlen(color_output_info[i]))) { + return i; + } + } + /* found failed */ + return -1; +#else + switch (log[0]) { + case 'A': return ELOG_LVL_ASSERT; + case 'E': return ELOG_LVL_ERROR; + case 'W': return ELOG_LVL_WARN; + case 'I': return ELOG_LVL_INFO; + case 'D': return ELOG_LVL_DEBUG; + case 'V': return ELOG_LVL_VERBOSE; + default: return -1; + } +#endif +} + +/** + * find the log tag + * @note make sure the log tag is output on each format + * @note the tag don't have space in it + * + * @param log log buffer + * @param lvl log level, you can get it by @see elog_find_lvl + * @param tag_len found tag length + * + * @return log tag, found failed will return NULL + */ +const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len) { + const char *tag = NULL, *tag_end = NULL; + + ELOG_ASSERT(log); + ELOG_ASSERT(tag_len); + ELOG_ASSERT(lvl < ELOG_LVL_TOTAL_NUM); + /* make sure the log tag is output on each format */ + ELOG_ASSERT(elog.enabled_fmt_set[lvl] & ELOG_FMT_TAG); + +#ifdef ELOG_COLOR_ENABLE + tag = log + strlen(CSI_START) + strlen(color_output_info[lvl]) + strlen(level_output_info[lvl]); +#else + tag = log + strlen(level_output_info[lvl]); +#endif + /* find the first space after tag */ + if ((tag_end = memchr(tag, ' ', ELOG_FILTER_TAG_MAX_LEN)) != NULL) { + *tag_len = tag_end - tag; + } else { + tag = NULL; + } + + return tag; +} diff --git a/easylogger/src/elog_async.c b/easylogger/src/elog_async.c index 86d23e0..52996e0 100644 --- a/easylogger/src/elog_async.c +++ b/easylogger/src/elog_async.c @@ -148,6 +148,58 @@ __exit: return size; } +#ifdef ELOG_ASYNC_LINE_OUTPUT +/** + * Get line log from asynchronous output ring buffer. + * It will copy all log when the newline sign isn't find. + * + * @param log get line log buffer + * @param size line log size + * + * @return get line log size, the log size is less than ring buffer used size + */ +size_t elog_async_get_line_log(char *log, size_t size) { + size_t used = 0, cpy_log_size = 0; + /* lock output */ + elog_output_lock(); + used = elog_async_get_buf_used(); + + /* no log */ + if (!used || !size) { + goto __exit; + } + /* less log */ + if (used <= size) { + size = used; + } + + if (read_index + size < ELOG_ASYNC_OUTPUT_BUF_SIZE) { + cpy_log_size = elog_cpyln(log, log_buf + read_index, size); + read_index += cpy_log_size; + } else { + cpy_log_size = elog_cpyln(log, log_buf + read_index, ELOG_ASYNC_OUTPUT_BUF_SIZE - read_index); + if (cpy_log_size == ELOG_ASYNC_OUTPUT_BUF_SIZE - read_index) { + cpy_log_size += elog_cpyln(log + cpy_log_size, log_buf, size - cpy_log_size); + read_index += cpy_log_size - ELOG_ASYNC_OUTPUT_BUF_SIZE; + } else { + read_index += cpy_log_size; + } + } + + if (used == cpy_log_size) { + buf_is_empty = true; + } + + if (cpy_log_size) { + buf_is_full = false; + } + +__exit: + /* lock output */ + elog_output_unlock(); + return cpy_log_size; +} +#else /** * get log from asynchronous output ring buffer * @@ -162,7 +214,7 @@ size_t elog_async_get_log(char *log, size_t size) { elog_output_lock(); used = elog_async_get_buf_used(); /* no log */ - if (!used) { + if (!used || !size) { size = 0; goto __exit; } @@ -189,6 +241,7 @@ __exit: elog_output_unlock(); return size; } +#endif /* ELOG_ASYNC_LINE_OUTPUT */ void elog_async_output(const char *log, size_t size) { /* this function must be implement by user when ELOG_ASYNC_OUTPUT_USING_PTHREAD is not defined */ @@ -222,7 +275,13 @@ static void *async_output(void *arg) { sem_wait(&output_notice); /* polling gets and outputs the log */ while(true) { - get_log_size = elog_async_get_log(poll_get_buf, sizeof(poll_get_buf)); + +#ifdef ELOG_ASYNC_LINE_OUTPUT + get_log_size = elog_async_get_line_log(poll_get_buf, ELOG_ASYNC_POLL_GET_LOG_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); } else { diff --git a/easylogger/src/elog_utils.c b/easylogger/src/elog_utils.c index 2d39f4f..c4f9754 100644 --- a/easylogger/src/elog_utils.c +++ b/easylogger/src/elog_utils.c @@ -27,6 +27,20 @@ */ #include +#include + +#define LOG_TAG "elog.utils" +#define assert ELOG_ASSERT +#define log_e(...) elog_e(LOG_TAG, __VA_ARGS__) +#define log_w(...) elog_w(LOG_TAG, __VA_ARGS__) + +#ifdef ELOG_DEBUG + #define log_d(...) elog_d(LOG_TAG, __VA_ARGS__) + #define log_v(...) elog_v(LOG_TAG, __VA_ARGS__) +#else + #define log_d(...) + #define log_v(...) +#endif /** * another copy string function @@ -39,6 +53,10 @@ */ size_t elog_strcpy(size_t cur_len, char *dst, const char *src) { const char *src_old = src; + + assert(dst); + assert(src); + while (*src != 0) { /* make sure destination has enough space */ if (cur_len++ <= ELOG_LINE_BUF_SIZE) { @@ -49,3 +67,28 @@ size_t elog_strcpy(size_t cur_len, char *dst, const char *src) { } return src - src_old; } + +/** + * Copy line log split by newline sign. It will copy all log when the newline sign isn't find. + * + * @param line line log buffer + * @param log origin log buffer + * @param len origin log buffer length + * + * @return copy size + */ +size_t elog_cpyln(char *line, const char *log, size_t len) { + size_t newline_len = strlen(ELOG_NEWLINE_SIGN), copy_size = 0; + + assert(log); + assert(line); + + while (len--) { + *line++ = *log++; + copy_size++; + if (copy_size >= newline_len && !strncmp(log - newline_len, ELOG_NEWLINE_SIGN, newline_len)) { + break; + } + } + return copy_size; +}