From 4cef7dd13e2a54b9fea625249a85c3a52f175ce4 Mon Sep 17 00:00:00 2001 From: wdfk-prog <1425075683@qq.com> Date: Sun, 29 Jan 2023 13:25:38 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ULOG=E9=AB=98=E7=BA=A7?= =?UTF-8?q?=E5=8A=9F=E8=83=BD,=E6=B7=BB=E5=8A=A0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9A=84=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=20=E6=A0=B9=E6=8D=AE=E6=96=87=E7=AB=A0>=20https://club.rt-thre?= =?UTF-8?q?ad.org/ask/article/73cedec4f1707abf.html=20=E7=BC=96=E5=86=99?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wdfk-prog <1425075683@qq.com> --- .../programming-manual/ulog/ulog.md | 280 ++++++++++++------ 1 file changed, 191 insertions(+), 89 deletions(-) diff --git a/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog.md b/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog.md index 659632a..c810ca0 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/ulog/ulog.md @@ -78,13 +78,13 @@ ENV 工具中使用 menuconfig 配置 ulog 的路径如下所示: 日志级别代表了日志的重要性,在 ulog 中由高到低,有如下几个日志级别: -| **级别** | **名称** | **描述** | -| ------------ | ---- | ----------------------- | -| LOG_LVL_ASSERT | 断言 | 发生无法处理、致命性的的错误,以至于系统无法继续运行的断言日志 | -| LOG_LVL_ERROR | 错误 | 发生严重的、**不可修复**的错误时输出的日志属于错误级别日志 | -| LOG_LVL_WARNING | 警告 | 出现一些不太重要的、具有**可修复性**的错误时,会输出这些警告日志 | -| LOG_LVL_INFO | 信息 | 给本模块上层使用人员查看的重要提示信息日志,例如:初始化成功,当前工作状态等。该级别日志一般在量产时依旧**保留**| -| LOG_LVL_DBG | 调试 | 给本模块开发人员查看的调试日志,该级别日志一般在量产时**关闭**| +| **级别** | **名称** | **描述** | +| --------------- | -------- | ------------------------------------------------------------ | +| LOG_LVL_ASSERT | 断言 | 发生无法处理、致命性的的错误,以至于系统无法继续运行的断言日志 | +| LOG_LVL_ERROR | 错误 | 发生严重的、**不可修复**的错误时输出的日志属于错误级别日志 | +| LOG_LVL_WARNING | 警告 | 出现一些不太重要的、具有**可修复性**的错误时,会输出这些警告日志 | +| LOG_LVL_INFO | 信息 | 给本模块上层使用人员查看的重要提示信息日志,例如:初始化成功,当前工作状态等。该级别日志一般在量产时依旧**保留** | +| LOG_LVL_DBG | 调试 | 给本模块开发人员查看的调试日志,该级别日志一般在量产时**关闭** | 在 ulog 中日志级别还有如下分类: @@ -130,10 +130,10 @@ ENV 工具中使用 menuconfig 配置 ulog 的路径如下所示: int ulog_init(void) ``` -| **返回** | **描述** | -| :----- | :----- | -|>=0 | 成功 | -|-5 | 失败,内存不足 | +| **返回** | **描述** | +| :------- | :------------- | +| >=0 | 成功 | +| -5 | 失败,内存不足 | 在使用 ulog 前必须调用该函数完成 ulog 初始化。如果开启了组件自动初始化,该函数也将被自动调用。 @@ -162,14 +162,14 @@ ulog 主要有两种日志输出宏 API,源代码中定义如下所示: * 宏 `ulog_x(LOG_TAG, __VA_ARGS__)`:`x` 对应的是不同级别的简写。参数 `LOG_TAG` 为日志标签,参数 `...` 为日志内容,格式与 printf 一致。这个 API 适用于在一个文件中使用不同 tag 输出日志的情况。 -| **API** |**描述** | -|-------------------------|--------------------------| -| LOG_E(...)| 错误级别日志 | -| LOG_W(...) | 错误级别日志 | -| LOG_I(...) | 提示级别日志 | -| LOG_D(...)| 调试级别日志 | -| LOG_RAW(...) | 输出 raw 日志 | -| LOG_HEX(name, width, buf, size)| 输出 16 进制格式数据到日志 | +| **API** | **描述** | +| ------------------------------- | -------------------------- | +| LOG_E(...) | 错误级别日志 | +| LOG_W(...) | 错误级别日志 | +| LOG_I(...) | 提示级别日志 | +| LOG_D(...) | 调试级别日志 | +| LOG_RAW(...) | 输出 raw 日志 | +| LOG_HEX(name, width, buf, size) | 输出 16 进制格式数据到日志 | `LOG_X` 及 `ulog_x` 这类 API 输出都是带格式日志,有些时候需要输出不带任何格式的日志时,可以使用 `LOG_RAW` 或 `ulog_raw()` 。例如: @@ -180,12 +180,12 @@ ulog_raw("\033[2A"); 以 16 进制 hex 格式 dump 数据到日志中可使用可以使用 `LOG_HEX()` 或 `ulog_hex` 。函数参数及描述如下所示: -| **参数** | **描述** | -| ---- | -------------------------- | -| tag | 日志标签 | -| width | 一行 hex 内容的宽度(数量) | -| buf | 待输出的数据内容 | -| size | 数据大小 | +| **参数** | **描述** | +| -------- | --------------------------- | +| tag | 日志标签 | +| width | 一行 hex 内容的宽度(数量) | +| buf | 待输出的数据内容 | +| size | 数据大小 | hexdump 日志为 DEBUG 级别,支持运行期的级别过滤,hexdump 日志对应的 tag ,支持运行期的标签过滤。 @@ -319,13 +319,13 @@ ulog_hexdump("buf_dump_test", 16, buf, sizeof(buf)); rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool_t support_color) ``` -| **参数** | **描述** | -| :----- | :----- | -|backend | 要注册的后端设备句柄 | -|name| 后端设备名称 | -|support_color| 是否支持彩色日志 | -|**返回**|-- | -|>=0 | 成功 | +| **参数** | **描述** | +| :------------ | :------------------- | +| backend | 要注册的后端设备句柄 | +| name | 后端设备名称 | +| support_color | 是否支持彩色日志 | +| **返回** | -- | +| >=0 | 成功 | 该函数用于将后端设备注册到 ulog 中,注册前确保后端设备结构体中的函数成员已设置。 @@ -335,11 +335,11 @@ rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool rt_err_t ulog_backend_unregister(ulog_backend_t backend); ``` -| **参数** | **描述** | -| :----- | :----- | -|backend | 要注销的后端设备句柄 | -|**返回**|-- | -|>=0 | 成功 | +| **参数** | **描述** | +| :------- | :------------------- | +| backend | 要注销的后端设备句柄 | +| **返回** | -- | +| >=0 | 成功 | 该函数用于注销已经注册的后端设备。 @@ -395,13 +395,115 @@ struct ulog_backend 从这个结构体的角度可以看出,实现后端设备的要求如下: * `name` 以及 `support_color` 属性可以通过 `ulog_backend_register` 函数在注册时传入。 - * `output` 为后端具体的输出函数,所有后端都必须实现接口。 - * `init`/`deinit` 可选择性实现,init 会在 register 时调用,deinit 会在 ulog_deinit 时调用。 - * `flush` 也是可选择性实现,一些内部输出带缓存的后端需要必须实现该接口 。比如一些带RAM 缓存的文件系统。后端的 flush 一般会在断言、hardfault 等异常情况下由 `ulog_flush` 完成调用。 +##### 文件后端注册示例 + +如下代码将实现一个文件后端的实现示例,将输出日志保存至文件系统路径`/flash/log`中. +详细配置`https://club.rt-thread.org/ask/article/73cedec4f1707abf.html` + +```c +#include + +/* +* 后端注册表 +*/ +struct _log_file +{ + const char *name; //文件名 + ulog_backend_t backend; + struct ulog_file_be *file_be; + const char *dir_path; //保存路径 + rt_size_t max_num; //保存最大文件数量 + rt_size_t max_size; //保存最大文件大小 + rt_size_t buf_size; //文件保存缓存大小 +}; +/* +* 文件后端标识 +*/ +typedef enum +{ + console_id, + sys_id, + motion_id, +}ulog_file_be_name; + +#define ROOT_PATH "/flash/log" //设置保存路径 +#define FILE_SIZE 512 * 1024 //设置单个文件大小 +#define BUFF_SIZE 512 //设备缓存区大小 + +static struct ulog_backend sys_log_backend; +static struct ulog_file_be sys_log_file; + +static struct _log_file table[] = +{ + {"sys" ,&sys_log_backend,&sys_log_file,ROOT_PATH,10,FILE_SIZE,BUFF_SIZE}, +}; +/* Private function prototypes -----------------------------------------------*/ +/** + * @brief 系统日志文件后端初始化. + * @param None. + * @retval None. + * @note None. +*/ +void sys_log_file_backend_init(void) +{ + struct ulog_file_be *file_be = &sys_log_file; + uint8_t id = sys_id; + file_be->parent = sys_log_backend; + + ulog_file_backend_init( file_be, + table[id].name, + table[id].dir_path, + table[id].max_num, + table[id].max_size, + table[id].buf_size); + + ulog_file_backend_enable(file_be); //必须使能才能有效 +} +``` + +添加如下代码实现文件后端滤波功能. + +```c +/** + * @brief 系统日志文件后端滤波器设置. + * @param None. + * @retval The filter will be call before output. It will return TRUE when the filter condition is math. + * @note None. +*/ +static rt_bool_t sys_log_file_backend_filter(struct ulog_backend *backend, rt_uint32_t level, const char *tag, rt_bool_t is_raw, + const char *log, rt_size_t len) +{ + //设置滤波规则,可以自己编写代码实现不同滤波规则 + if (rt_strncmp(tag,MOTION_TAG, sizeof(MOTION_TAG)) == 0)//排除带有"MOVE"标签输出 + return RT_FALSE; + else + return RT_TRUE; + + //if (rt_strncmp(tag,MOTION_TAG, sizeof(MOTION_TAG)) == 0)//带有"MOVE"标签输出 + // return RT_TRUE; + //else + // return RT_FALSE; +} + +void sys_log_file_backend_init(void) +{ + //添加 + ulog_backend_filter_t filter = sys_log_file_backend_filter; + + ... + + ulog_file_backend_enable(file_be); + //添加 + ulog_backend_set_filter(&file_be->parent,filter); +} +``` + + + ### 异步日志 在 ulog 中,默认的输出模式是同步模式,在很多场景下用户可能还需要异步模式。用户在调用日志输出 API 时,会将日志缓存到缓冲区中,会有专门负责日志输出的线程取出日志,然后输出到后端。 @@ -469,13 +571,13 @@ ulog 支持的动态过滤方式有以下 4 种,并且都有对应的 API 函 int ulog_tag_lvl_filter_set(const char *tag, rt_uint32_t level) ``` -| **参数** | **描述** | -| ------- | ------------------------------ | -| tag | 日志的标签 | -| level | 设定的日志级别 | -|**返回**|-- | -| >=0 | 成功 | -| -5 | 失败,没有足够的内存 | +| **参数** | **描述** | +| -------- | -------------------- | +| tag | 日志的标签 | +| level | 设定的日志级别 | +| **返回** | -- | +| >=0 | 成功 | +| -5 | 失败,没有足够的内存 | * 命令格式: `ulog_tag_lvl ` @@ -483,21 +585,21 @@ int ulog_tag_lvl_filter_set(const char *tag, rt_uint32_t level) 参数 level 日志级别可取如下值: -|**级别** |**名称** | **取值**| -| --------------------- | ---------------- |-| -| LOG_LVL_ASSERT | 断言 |0| -| LOG_LVL_ERROR | 错误 |3| -| LOG_LVL_WARNING | 警告 |4| -| LOG_LVL_INFO | 信息 |6| -| LOG_LVL_DBG | 调试 |7| -| LOG_FILTER_LVL_SILENT | 静默(停止输出) |0| -| LOG_FILTER_LVL_ALL | 全部 |7| +| **级别** | **名称** | **取值** | +| --------------------- | ---------------- | -------- | +| LOG_LVL_ASSERT | 断言 | 0 | +| LOG_LVL_ERROR | 错误 | 3 | +| LOG_LVL_WARNING | 警告 | 4 | +| LOG_LVL_INFO | 信息 | 6 | +| LOG_LVL_DBG | 调试 | 7 | +| LOG_FILTER_LVL_SILENT | 静默(停止输出) | 0 | +| LOG_FILTER_LVL_ALL | 全部 | 7 | 函数调用与命令示例如下所示: -| 功能 | 函数调用 | 执行命令 | -| ---------------- | ------------------------------ | ------------------ | -| 关闭 `wifi` 模块全部日志 | `ulog_tag_lvl_filter_set("wifi", LOG_FILTER_LVL_SILENT);` | `ulog_tag_lvl wifi 0` | +| 功能 | 函数调用 | 执行命令 | +| ------------------------------ | --------------------------------------------------------- | --------------------- | +| 关闭 `wifi` 模块全部日志 | `ulog_tag_lvl_filter_set("wifi", LOG_FILTER_LVL_SILENT);` | `ulog_tag_lvl wifi 0` | | 开启 `wifi` 模块全部日志 | `ulog_tag_lvl_filter_set("wifi", LOG_FILTER_LVL_ALL);` | `ulog_tag_lvl wifi 7` | | 设置 `wifi` 模块日志级别为警告 | `ulog_tag_lvl_filter_set("wifi", LOG_LVL_WARNING);` | `ulog_tag_lvl wifi 4` | @@ -507,9 +609,9 @@ int ulog_tag_lvl_filter_set(const char *tag, rt_uint32_t level) void ulog_global_filter_tag_set(const char *tag) ``` -| **参数** | **描述** | -| :--- | :------------- | -| tag | 设定的过滤标签 | +| **参数** | **描述** | +| :------- | :------------- | +| tag | 设定的过滤标签 | * 命令格式: `ulog_tag [tag]` ,tag 为空时,则取消标签过滤。 @@ -517,11 +619,11 @@ void ulog_global_filter_tag_set(const char *tag) 例如:有 `wifi.driver` 、 `wifi.mgnt` 、`audio.driver` 3 种标签的日志,当设定过滤标签为 `wifi` 时,只有标签为 `wifi.driver` 及 `wifi.mgnt` 的日志会输出。同理,当设置过滤标签为 `driver` 时,只有标签为 `wifi.driver` 及 `audio.driver` 的日志会输出。常见功能对应的函数调用与命令示例如下: -| 功能 | 函数调用 | 执行命令 | -| -------------| -------------------- | ---------- | +| 功能 | 函数调用 | 执行命令 | +| ------------------------ | --------------------------------------- | ----------------- | | 设置过滤标签为 `wifi` | `ulog_global_filter_tag_set("wifi");` | `ulog_tag wifi` | | 设置过滤标签为 `driver` | `ulog_global_filter_tag_set("driver");` | `ulog_tag driver` | -| 取消标签过滤 | `ulog_global_filter_tag_set("");` | `ulog_tag` | +| 取消标签过滤 | `ulog_global_filter_tag_set("");` | `ulog_tag` | #### 按级别全局过滤 @@ -529,24 +631,24 @@ void ulog_global_filter_tag_set(const char *tag) void ulog_global_filter_lvl_set(rt_uint32_t level) ``` -| **参数** | **描述** | -| ---- | -------------------| -| level | 设定的日志级别 | +| **参数** | **描述** | +| -------- | -------------- | +| level | 设定的日志级别 | * 命令格式: `ulog_lvl ` ,level 取值参照下表: -| **取值** | **描述** | -| :------------ | :--------------- | -| 0 | 断言 | -| 3 | 错误 | -| 4 | 警告 | -| 6 | 信息 | -| 7 | 调试 | +| **取值** | **描述** | +| :------- | :------- | +| 0 | 断言 | +| 3 | 错误 | +| 4 | 警告 | +| 6 | 信息 | +| 7 | 调试 | 通过函数或者命令设定好全局的过滤级别以后,**低于设定级别**的日志都将停止输出。常见功能对应的函数调用与命令示例如下: -| 功能 | 函数调用 | 执行命令 | -| ----------| ------------------------------ | ------- | +| 功能 | 函数调用 | 执行命令 | +| ------------------ | ---------------------------------------------------- | ------------ | | 关闭全部日志 | `ulog_global_filter_lvl_set(LOG_FILTER_LVL_SILENT);` | `ulog_lvl 0` | | 开启全部日志 | `ulog_global_filter_lvl_set(LOG_FILTER_LVL_ALL);` | `ulog_lvl 7` | | 设置日志级别为警告 | `ulog_global_filter_lvl_set(LOG_LVL_WARNING);` | `ulog_lvl 4` | @@ -557,16 +659,16 @@ void ulog_global_filter_lvl_set(rt_uint32_t level) void ulog_global_filter_kw_set(const char *keyword) ``` -| **参数** | **描述** | -| :------ | :--------------- | -| keyword | 设定的过滤关键词 | +| **参数** | **描述** | +| :------- | :--------------- | +| keyword | 设定的过滤关键词 | * 命令格式: `ulog_kw [keyword]` ,keyword 为空时,则取消关键词过滤。 该过滤方式可以对所有日志执行按关键词过滤,**包含关键词信息**的日志才允许输出。常见功能对应的函数调用与命令示例如下: -| 功能 | 函数调用 | 执行命令 | -| -------------- | ------------------- | --------- | +| 功能 | 函数调用 | 执行命令 | +| ----------------------- | ------------------------------------ | -------------- | | 设置过滤关键词为 `wifi` | `ulog_global_filter_kw_set("wifi");` | `ulog_kw wifi` | | 清空过滤关键词 | `ulog_global_filter_kw_set("");` | `ulog_kw` | @@ -701,12 +803,12 @@ ulog 提供了 syslog 模式的支持,不仅仅前端 API 与 syslog API 完 如上图所示,ulog syslog 日志格式分为下面 4 个部分: -| 格式 | **描述** | -| ---- | --------------------- | -| PRI | PRI 部分由尖括号包含的一个数字构成,这个数字包含了程序模块(Facility)、严重性(Severity)信息,是由 Facility 乘以 8,然后加上 Severity 得来。 Facility 和 Severity 由 syslog 函数的入参传入,具体数值详见 syslog.h | -| Header | Header 部分主要是时间戳,指示当前日志的时间; | -| TAG | 当前日志的标签,可以通过 openlog 函数入参传入,如果不指定将会使用 rtt 作为默认标签 | -| Content | 日志的具体内容 | +| 格式 | **描述** | +| ------- | ------------------------------------------------------------ | +| PRI | PRI 部分由尖括号包含的一个数字构成,这个数字包含了程序模块(Facility)、严重性(Severity)信息,是由 Facility 乘以 8,然后加上 Severity 得来。 Facility 和 Severity 由 syslog 函数的入参传入,具体数值详见 syslog.h | +| Header | Header 部分主要是时间戳,指示当前日志的时间; | +| TAG | 当前日志的标签,可以通过 openlog 函数入参传入,如果不指定将会使用 rtt 作为默认标签 | +| Content | 日志的具体内容 | #### 使用方法 @@ -798,4 +900,4 @@ ulog 提供了多种维度的日志开关、过滤的功能,完全能够做到 **Q:** 编译时提示:The idle thread stack size must more than 384 when using async output by idle (ULOG_ASYNC_OUTPUT_BY_IDLE)。 -**A:** 在使用 idle 线程作为输出线程时,idle 线程的堆栈大小需要提高,这也取决于具体的后端设备,例如:控制台后端时,idle 线程至少得 384 字节。 +**A:** 在使用 idle 线程作为输出线程时,idle 线程的堆栈大小需要提高,这也取决于具体的后端设备,例如:控制台后端时,idle 线程至少得 384 字节。 \ No newline at end of file -- Gitee