目錄
前言
使用場景
實現功能
具體操作
1 前言
在項目開發中需要使用到日志功能來調試和查看問題。有些問題并不會在我們實時查看的時候發生,而是在你上個廁所的功夫可能就發生了。如果上位機的緩沖區不夠大,可能錯誤日志都看不到。
這時候就很有必要把日志文件保存在文件系統中了。RTT軟件包中ULOG_FILE這個包可以實現日志文件的保存,但是它兩年沒更新了,另一個是會把所有日志保存起來。并不能按不同的標簽分開保存。
還好現在的ulog組件自帶了文件后端,只需要我們去配置就好了。
2 使用場景
在實際應用中,有些日志信息需要不間斷輸出并保存。例如AGV的運動信息,電池電量等等。
這些信息如果不作處理,會一并打印在控制臺上,影響查看重要信息與輸入MSH命令
3 實現功能
所以需要一個文件來實現:
1.日志分開保存在不同文件內。
2.控制臺可以按需求顯示與不顯示某類信息。
4 具體操作
0.前提配置
1.ULOG組件勾選并使用異步模式。
2.使用一個文件系統來保存文件
3.ULOG組件勾選文件后端

4.先確保文件系統能夠正常讀寫,創建,刪除
1.新建一個注冊表,把目錄,文件名,大小,數量寫入表內
BUFF_SIZE這個緩沖區代表多少大小再進行一次寫入,緩沖區太大,會很久才更改一次。
BUFF_SIZE太小會寫入太頻繁,導致ULOG異步線程堆棧不夠溢出
ROOT_PATH是保存的路徑。我選擇“/flash/log”是因為我使用了ROM系統保存根目錄,根目錄是只讀的。只有/flash下的文件夾才是可讀寫的。
上下左右滑動閱覽
struct_log_file{constchar*name;constchar*dir_path;rt_size_tmax_num;rt_size_tmax_size;rt_size_tbuf_size;};#defineROOT_PATH"/flash/log"#defineFILE_SIZE 512 * 1024#defineBUFF_SIZE 512staticstruct_log_filetable[] ={{"sys" ,ROOT_PATH,10,FILE_SIZE,BUFF_SIZE},{"motion" ,ROOT_PATH,5,FILE_SIZE,BUFF_SIZE},};
2.進行文件后端初始化
注意init后一定要enbale,不然沒有運行
上下左右滑動閱覽
staticstructulog_backendsys_log_backend;staticstructulog_file_besys_log_file;voidsys_log_file_backend_init(void){ structulog_file_be *file_be = &sys_log_file; uint8_tid= sys_id; file_be->parent = sys_log_backend; ulog_backend_filter_tfilter= sys_log_file_backend_filter; 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);}staticstructulog_backendmotion_log_backend;staticstructulog_file_bemotion_log_file;voidmotion_log_file_backend_init(void){ structulog_file_be *file_be = &motion_log_file; uint8_tid= motion_id; file_be->parent = motion_log_backend; ulog_backend_filter_tfilter= motion_log_file_backend_filter; 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);}
3.測試運行
這個時候就可以先測試一下,看看日志有沒有都保存在兩個文件內
后綴名都是.log

使用cat命令查看一下內容

4.分開保存不同日志
上一步只進行了同時保存在兩個文件內。還需要保存不同的日志內容。
1.在初始化函數中加入濾波函數設置
上下左右滑動閱覽
voidsys_log_file_backend_init(void){ ulog_backend_filter_t filter = sys_log_file_backend_filter; ulog_backend_set_filter(&file_be->parent,filter);}
2.編寫濾波函數
這個函數是自己編寫的,比如系統日志文件不需要標簽帶有”MOVE”的
上下左右滑動閱覽
#defineMOTION_TAG "MOVE"staticrt_bool_tsys_log_file_backend_filter(structulog_backend *backend,rt_uint32_tlevel, constchar *tag,rt_bool_tis_raw, constchar *log,rt_size_tlen){ if(rt_strncmp(tag,MOTION_TAG,sizeof(MOTION_TAG)) ==0)//排除帶有"MOVE"標簽輸出 returnRT_FALSE; else returnRT_TRUE;}
比如運動日志文件只需要標簽帶有”MOVE”的
上下左右滑動閱覽
staticrt_bool_tmotion_log_file_backend_filter(structulog_backend *backend,rt_uint32_tlevel, constchar *tag,rt_bool_tis_raw, constchar *log,rt_size_tlen){ if(rt_strncmp(tag,MOTION_TAG,sizeof(MOTION_TAG)) ==0)//帶有"MOVE"標簽輸出 returnRT_TRUE; else returnRT_FALSE;}
3.在一個線程中使用帶特定標簽的日志輸出看一下效果
上下左右滑動閱覽
#define LOG_MV(...) ulog_i(MOTION_TAG, __VA_ARGS__)while(1){ set_angle +=0.1; get_angle -=0.1; set_speed +=1; get_speed -=1; vaule +=3.14; LOG_MV("%f%f%d%f%f", set_angle,get_angle,set_speed, get_speed,vaule); rt_thread_mdelay(500);}
大小不同的保存文件

一個是系統日志

一個是運動日志

內容也不同,搞定完成
5.實現文件后端輸出功能的關閉與打開
像易掉電的嵌入式使用FLASH或者EEPROM,容易在進行文件操作時掉電,導致文件損壞。另一個就是文件打開狀態下,是不能刪除的。有的時候又需要清除無用的日志文件。這就需要實現可以對文件后端進行控制
1.控制日志是否輸出到文件中
上下左右滑動閱覽
staticvoidlog_file_backend_control(uint8_t argc, char**argv){ constchar*operator=argv[1]; constchar*flag=argv[2]; if(argc3)? {? ? ? rt_kprintf("Usage:\n");? ? ? rt_kprintf("control ulog file backend [name] [enable/disable]\n");? ? ? return;? }? elseif(!rt_strcmp(operator,table[sys_id].name))? {? ? if(!rt_strcmp(flag,"disable"))? ? {? ? ? ulog_file_backend_disable(&sys_log_file);? ? ? rt_kprintf("The file backend %s is disabled\n",operator);? ? }? ? elseif(!rt_strcmp(flag,"enable"))? ? {? ? ? ulog_file_backend_enable(&sys_log_file);? ? ? rt_kprintf("The file backend %s is enable\n",operator);? ? }? ? else? ? {? ? ? rt_kprintf("Usage:\n");? ? ? rt_kprintf("control ulog file backend [name] [enable/disable]\n");? ? ? return;? ? }? }? elseif(!rt_strcmp(operator,table[motion_id].name))? {? ? if(!rt_strcmp(flag,"disable"))? ? {? ? ? ulog_file_backend_disable(&motion_log_file);? ? ? rt_kprintf("The file backend %s is disabled\n",operator);? ? }? ? elseif(!rt_strcmp(flag,"enable"))? ? {? ? ? ulog_file_backend_enable(&motion_log_file);? ? ? rt_kprintf("The file backend %s is enable\n",operator);? ? }? ? else? ? {? ? ? rt_kprintf("Usage:\n");? ? ? rt_kprintf("control ulog file backend [name] [enable/disable]\n");? ? ? return;? ? }? }? else? {? ? rt_kprintf("Failed to find the file backend:%s\n",operator);? }}MSH_CMD_EXPORT_ALIAS(log_file_backend_control,ulog_be_ctrl,control ulog file backend [name] [enable:disable]);
2.控制日志文件后端卸載,來刪除文件
上下左右滑動閱覽
staticvoidlog_file_backend_deinit(uint8_t argc, char**argv){ constchar*operator=argv[1]; if(argc2)? {? ? ? rt_kprintf("Usage:\n");? ? ? rt_kprintf("Deinit ulog file backend [name]\n");? ? ? return;? }? else? {? ? if(!rt_strcmp(operator,"motion"))? ? {? ? ? ulog_file_backend_deinit(&motion_log_file);? ? ? ulog_file_backend_disable(&motion_log_file);? ? ? rt_kprintf("The file backend %s is deinit\n",operator);? ? }? ? elseif(!rt_strcmp(operator,"sys"))? ? {? ? ? ulog_file_backend_deinit(&sys_log_file);? ? ? ulog_file_backend_disable(&sys_log_file);? ? ? rt_kprintf("The file backend %s is deinit\n",operator);? ? }? ? else? ? {? ? ? rt_kprintf("Usage:\n");? ? ? rt_kprintf("Deinit ulog file backend [name]\n");? ? ? return;? ? }? }}MSH_CMD_EXPORT_ALIAS(log_file_backend_deinit,ulog_be_deinit,Deinit?ulog file backend);
6.擴展功能,顯示與不顯示特定日志到控制臺上
按照上面操作下來,基本功能都完成了。還差一個控制臺可以按需求顯示與不顯示某類信息。
不實現這個,會導致控制臺信息一直在輸出,無法查看重要信息,不好輸入命令
1.對console_be.c進行改造
增加ulog_console_backend_filter函數的弱定義,可以在其他地方進行實現
在控制臺初始化時,掛鉤ulog_console_backend_filter函數
上下左右滑動閱覽
RT_WEAKrt_bool_tulog_console_backend_filter(struct ulog_backend *backend, rt_uint32_t level, constchar *tag, rt_bool_t is_raw,constchar *log, rt_size_t len){ returnRT_TRUE;}intulog_console_backend_init(void){ ulog_init(); console.output= ulog_console_backend_output; ulog_backend_register(&console,"console",RT_TRUE); ulog_backend_set_filter(&console,ulog_console_backend_filter); return0;}INIT_PREV_EXPORT(ulog_console_backend_init);
2.實現ulog_console_backend_filter函數,過濾不需要顯示信息
上下左右滑動閱覽
rt_bool_tulog_console_backend_filter(structulog_backend *backend,rt_uint32_tlevel, constchar *tag,rt_bool_tis_raw, constchar *log,rt_size_tlen){ if(rt_strncmp(tag,MOTION_TAG,sizeof(MOTION_TAG)) ==0)//排除帶有"MOVE"標簽輸出 returnRT_FALSE; else returnRT_TRUE;}
3.增加MSH命令,用來控制控制臺需不需要查看信息
有些時候,日志文件輸出的不是實時的。打開文件查看也不方便。
能輸出到控制臺直接顯示是最合適不過
上下左右滑動閱覽
#ifdefRT_USING_MSHstaticvoidulog_console_backend_filter_set(uint8_targc,char**argv){ if(argc 2)? ? {? ? ? ? rt_kprintf("Usage:\n");? ? ? ? rt_kprintf("console filter [option] optino:enable or disable\n");? ? ? ? return;? ? }? ? else? ? {? ? ? ? constchar *operator?= argv[1];? ? ? ? if?(!rt_strcmp(operator,?"enable"))? ? ? ? {? ? ? ? ? ? ulog_backend_set_filter(&console,ulog_console_backend_filter);? ? ? ? }? ? ? ? elseif?(!rt_strcmp(operator,?"disable"))? ? ? ? {? ? ? ? ? ? ulog_backend_set_filter(&console,RT_NULL);? ? ? ? }? ? ? ? else? ? ? ? {? ? ? ? ? ? rt_kprintf("Usage:\n");? ? ? ? ? ? rt_kprintf("console filter [option] optino:enable or disable\n");? ? ? ? }? ? }}MSH_CMD_EXPORT_ALIAS(ulog_console_backend_filter_set,console_filter,console filter [option] optino:enable?or?disable);#endif
7.結束
以上就是全部內容了。
這個應用根據我在github上提出的問題實現的。
https://github.com/RT-Thread/rt-thread/issues/6567
之前也有這種需求,用的是另一種方式。
https://club.rt-thread.org/ask/article/e3ace649aea0ba5c.html
稍微提一句,MSH命令的控制函數沒有使用輸入文件后端的名稱去查找實現。因為ulog_backend_find()函數的返回只有ulog的后端指針,沒有file_be的指針,沒辦法操作。覺得ulog_backend的結構體可以加一個子對象,就像ulog_file_be的結構體加入了parent一樣
特此分享^~^
最后附上代碼文件
ulog_file_be.c(https://club.rt-thread.org/file_download/d845a228140ec38b)
ulog_file_be.h(https://club.rt-thread.org/file_download/ef9a1b046b884535)
console_be.c(https://club.rt-thread.org/file_download/0b4e0fd7bc8a566e)
【更新]
取消console_be.c的代碼
MSH命令改為使用ulog_be_cmd控制
支持控制臺操作

ulog_file_be.c(https://club.rt-thread.org/file_download/db82838a83e98553)
-
ROM
+關注
關注
4文章
579瀏覽量
89067 -
RT-Thread
+關注
關注
32文章
1613瀏覽量
44869 -
項目開發
+關注
關注
0文章
9瀏覽量
7498
發布評論請先 登錄
簡潔易用的日志系統 ulog 日志
如何使用RT-Thread Studio創建支持HPM6750開發板的RT-Thread項目
ULOG創建多個文件后端并保存不同日志方法
ulog_easyflash存滿后去讀取日志系統重啟咋辦
不知道rt-thread的ulog為什么可以在中斷中使用?
RT-Thread發布“超輕量級“日志組件ulog
RT-Thread Studio驅動SD卡
RT-Thread全球技術大會:Kconfig在RT-Thread中的工作機制
RT-Thread v5.0.2 發布
RT-Thread ULOG: 創建多個文件后端并保存不同日志方法 | 技術集結
評論