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

4.先確保文件系統(tǒng)能夠正常讀寫,創(chuàng)建,刪除
1.新建一個(gè)注冊表,把目錄,文件名,大小,數(shù)量寫入表內(nèi)
BUFF_SIZE這個(gè)緩沖區(qū)代表多少大小再進(jìn)行一次寫入,緩沖區(qū)太大,會很久才更改一次。
BUFF_SIZE太小會寫入太頻繁,導(dǎo)致ULOG異步線程堆棧不夠溢出
ROOT_PATH是保存的路徑。我選擇“/flash/log”是因?yàn)槲沂褂昧?a href="http://www.makelele.cn/tags/rom/" target="_blank">ROM系統(tǒng)保存根目錄,根目錄是只讀的。只有/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.進(jìn)行文件后端初始化
注意init后一定要enbale,不然沒有運(yùn)行
上下左右滑動閱覽
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.測試運(yùn)行
這個(gè)時(shí)候就可以先測試一下,看看日志有沒有都保存在兩個(gè)文件內(nèi)
后綴名都是.log

使用cat命令查看一下內(nèi)容

4.分開保存不同日志
上一步只進(jìn)行了同時(shí)保存在兩個(gè)文件內(nèi)。還需要保存不同的日志內(nèi)容。
1.在初始化函數(shù)中加入濾波函數(shù)設(shè)置
上下左右滑動閱覽
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.編寫濾波函數(shù)
這個(gè)函數(shù)是自己編寫的,比如系統(tǒng)日志文件不需要標(biāo)簽帶有”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"標(biāo)簽輸出 returnRT_FALSE; else returnRT_TRUE;}
比如運(yùn)動日志文件只需要標(biāo)簽帶有”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"標(biāo)簽輸出 returnRT_TRUE; else returnRT_FALSE;}
3.在一個(gè)線程中使用帶特定標(biāo)簽的日志輸出看一下效果
上下左右滑動閱覽
#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);}
大小不同的保存文件

一個(gè)是系統(tǒng)日志

一個(gè)是運(yùn)動日志

內(nèi)容也不同,搞定完成
5.實(shí)現(xiàn)文件后端輸出功能的關(guān)閉與打開
像易掉電的嵌入式使用FLASH或者EEPROM,容易在進(jìn)行文件操作時(shí)掉電,導(dǎo)致文件損壞。另一個(gè)就是文件打開狀態(tài)下,是不能刪除的。有的時(shí)候又需要清除無用的日志文件。這就需要實(shí)現(xiàn)可以對文件后端進(jìn)行控制
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.擴(kuò)展功能,顯示與不顯示特定日志到控制臺上
按照上面操作下來,基本功能都完成了。還差一個(gè)控制臺可以按需求顯示與不顯示某類信息。
不實(shí)現(xiàn)這個(gè),會導(dǎo)致控制臺信息一直在輸出,無法查看重要信息,不好輸入命令
1.對console_be.c進(jìn)行改造
增加ulog_console_backend_filter函數(shù)的弱定義,可以在其他地方進(jìn)行實(shí)現(xiàn)
在控制臺初始化時(shí),掛鉤ulog_console_backend_filter函數(shù)
上下左右滑動閱覽
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.實(shí)現(xiàn)ulog_console_backend_filter函數(shù),過濾不需要顯示信息
上下左右滑動閱覽
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"標(biāo)簽輸出 returnRT_FALSE; else returnRT_TRUE;}
3.增加MSH命令,用來控制控制臺需不需要查看信息
有些時(shí)候,日志文件輸出的不是實(shí)時(shí)的。打開文件查看也不方便。
能輸出到控制臺直接顯示是最合適不過
上下左右滑動閱覽
#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.結(jié)束
以上就是全部內(nèi)容了。
這個(gè)應(yīng)用根據(jù)我在github上提出的問題實(shí)現(xiàn)的。
https://github.com/RT-Thread/rt-thread/issues/6567
之前也有這種需求,用的是另一種方式。
https://club.rt-thread.org/ask/article/e3ace649aea0ba5c.html
稍微提一句,MSH命令的控制函數(shù)沒有使用輸入文件后端的名稱去查找實(shí)現(xiàn)。因?yàn)閡log_backend_find()函數(shù)的返回只有ulog的后端指針,沒有file_be的指針,沒辦法操作。覺得ulog_backend的結(jié)構(gòu)體可以加一個(gè)子對象,就像ulog_file_be的結(jié)構(gòu)體加入了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
+關(guān)注
關(guān)注
4文章
579瀏覽量
89045 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1611瀏覽量
44803 -
項(xiàng)目開發(fā)
+關(guān)注
關(guān)注
0文章
9瀏覽量
7496
發(fā)布評論請先 登錄
RT-Thread文件系統(tǒng)的基本知識和使用方法
RT-Thread Vector軟件包:嵌入式開發(fā)的動態(tài)數(shù)組容器 | 技術(shù)集結(jié)
簡潔易用的日志系統(tǒng) ulog 日志
如何使用RT-Thread Studio創(chuàng)建支持HPM6750開發(fā)板的RT-Thread項(xiàng)目
ULOG創(chuàng)建多個(gè)文件后端并保存不同日志方法
ulog_easyflash存滿后去讀取日志系統(tǒng)重啟咋辦
不知道rt-thread的ulog為什么可以在中斷中使用?
RT-Thread發(fā)布“超輕量級“日志組件ulog
RT-Thread Studio驅(qū)動SD卡
RT-Thread全球技術(shù)大會:螢石研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn)
RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機(jī)制
RT-Thread v5.0.2 發(fā)布
RT-Thread ULOG: 創(chuàng)建多個(gè)文件后端并保存不同日志方法 | 技術(shù)集結(jié)
評論