在我們嵌入式開(kāi)發(fā)中,打印日志是最常用的一種調(diào)試手段。合理地打印日志,可以幫助我們快速地分析問(wèn)題。
本篇文章我們來(lái)匯總一些嵌入式打log的一些規(guī)則。
1、什么操作下加日志?
(1)錯(cuò)誤處理
對(duì)于不能恢復(fù)的嚴(yán)重錯(cuò)誤,日志內(nèi)容應(yīng)詳細(xì)到足以幫助定位問(wèn)題,但同時(shí)不應(yīng)該包含敏感信息。比如申請(qǐng)內(nèi)存失敗時(shí)使用錯(cuò)誤(Error)級(jí)別加上日志信息。
(2)一些關(guān)鍵性的操作
一些很關(guān)鍵地處理,無(wú)論是正常情況或者異常情況都要打印日志。比如wifi打開(kāi)時(shí)要有對(duì)應(yīng)的日志信息。
(3)系統(tǒng)的打開(kāi)、關(guān)閉
記錄系統(tǒng)啟動(dòng)和關(guān)閉過(guò)程中的關(guān)鍵步驟有助于分析系統(tǒng)初始化是否正確,或者系統(tǒng)是否正常關(guān)閉。
(4)性能監(jiān)控
日志可以記錄系統(tǒng)運(yùn)行的關(guān)鍵性能指標(biāo),如CPU和內(nèi)存使用率、IO操作等,以便進(jìn)行系統(tǒng)性能分析和優(yōu)化。
(5)關(guān)鍵數(shù)據(jù)
一些關(guān)鍵數(shù)據(jù)需要打印,很多功能上的問(wèn)題大多直接與數(shù)據(jù)進(jìn)行掛鉤。
(6)通信日志
對(duì)于需要與外部設(shè)備或網(wǎng)絡(luò)通信的嵌入式系統(tǒng),記錄通信日志可以幫助分析和調(diào)試通信協(xié)議或數(shù)據(jù)交換的問(wèn)題。
(7)記錄用戶(hù)行為
在需要分析用戶(hù)如何與嵌入式設(shè)備交互的情況下,記錄用戶(hù)行為的日志會(huì)非常有幫助。
(8)if、switch
分支判斷中,各執(zhí)行分支需要加上對(duì)應(yīng)的日志信息,可以幫助我們準(zhǔn)確地知道程序執(zhí)行的走向。
(9)程序崩潰時(shí)的信息
比如,Linxu下應(yīng)用進(jìn)程崩潰時(shí)的調(diào)用堆棧信息。
#include#include #include #include voidfunc0(void) { printf("Thisisfunc0 "); int*p=NULL; *p=1234; } voidfunc1(void) { printf("Thisisfunc1 "); func0(); } voidfunc2(void) { printf("Thisisfunc2 "); func1(); } voiddump(intsigno) { void*array[100]; size_tsize; char**strings; size=backtrace(array,100); strings=backtrace_symbols(array,size); printf("Obtained%zdstacks. ",size); for(inti=0;i
2、功能模塊標(biāo)簽
項(xiàng)目中肯定會(huì)劃分有多個(gè)模塊,可以給各個(gè)模塊標(biāo)記一個(gè)模塊標(biāo)簽字符串,包含在日志條目里。這樣我們就可以在日志文件里通過(guò)模塊標(biāo)簽來(lái)篩選某個(gè)模塊的日志,提高我們定位問(wèn)題的效率。
比如:
//app_wifi.c #defineLOG_TAG"[wifi_module]" #defineLOG_D(fmt,arg...)LOG_D_TAG(LOG_TAG,fmt,##arg) LOG_D("hellowifimodule");
輸出:
[wifi_module]hellowifimodule
3、模塊日志開(kāi)關(guān)
設(shè)置模塊日志開(kāi)關(guān),可以方便我們調(diào)試、分析問(wèn)題時(shí),縮小分析范圍。當(dāng)我們的函數(shù)設(shè)計(jì)有多個(gè)功能函數(shù)模塊的時(shí)候,當(dāng)某個(gè)模塊出現(xiàn)問(wèn)題時(shí),這個(gè)時(shí)候我們只是關(guān)心此模塊,那么可以先把其他模塊的日志功能關(guān)閉掉,只是打開(kāi)關(guān)心模塊的日志。
如:
//module1.c #include"module1.h" #ifMODULE1_LOG_SWITCH #defineLOG_MODULE1(fmt,args...)DBG_PRINTF(fmt,##args) #else #defineLOG_MODULE1(fmt,args...) #endif //module2.c #include"module2.h" #ifMODULE2_LOG_SWITCH #defineLOG_MODULE2(fmt,args...)DBG_PRINTF(fmt,##args) #else #defineLOG_MODULE2(fmt,args...) #endif //config.h #defineMODULE1_LOG_SWITCH0 #defineMODULE2_LOG_SWITCH1
4、時(shí)間戳
日志應(yīng)包含時(shí)間戳,可以方便地查看某段代碼的執(zhí)行時(shí)間、確定問(wèn)題發(fā)生的具體時(shí)間。時(shí)間戳最好能精確到微秒/毫秒。
5、日志級(jí)別
使用不同的日志級(jí)別可以幫助篩選和控制輸出的信息量。
常見(jiàn)的日志級(jí)別包括:
錯(cuò)誤(Error):程序無(wú)法運(yùn)行或嚴(yán)重問(wèn)題。
警告(Warning):可能的問(wèn)題,程序可以繼續(xù)運(yùn)行。
信息(Info):程序運(yùn)行狀態(tài)信息。
調(diào)試(Debug):詳細(xì)的調(diào)試信息,包括變量值和程序流程。
詳細(xì)(Verbose):非常詳細(xì)的信息,用于深入調(diào)試。
6、格式統(tǒng)一
為了使日志易于閱讀,所有日志應(yīng)保持一致的格式。
日志里常包含的固定信息有:
文件名
行號(hào)
時(shí)間日期/時(shí)間戳
函數(shù)名
模塊名稱(chēng)
進(jìn)程ID
線程ID
可根據(jù)需要進(jìn)行組合。如:
[2024-01-1411:12:30.666][wifi_module][func:wifi_init]
7、過(guò)濾控制
使用日志動(dòng)態(tài)過(guò)濾控制功能可以動(dòng)態(tài)地調(diào)整日志地輸出,但前提是項(xiàng)目使用地日志組件具備這樣的能力。比如EasyLogger(https://github.com/armink/EasyLogger)。
8、Release/Debug開(kāi)關(guān)
由于日志打印可能占用不少系統(tǒng)資源,應(yīng)當(dāng)注意其對(duì)性能的影響。在Release版本中,可能需要減少日志輸出或者去掉一些不必要的日志,需要一個(gè)開(kāi)關(guān)來(lái)進(jìn)行切換。
9、封裝日志接口
嵌入式中,日志的輸出大多數(shù)情況下會(huì)輸出到串口終端。但也有一些場(chǎng)景,需要把日志輸出到屏幕、網(wǎng)絡(luò)設(shè)備、定制化的上位機(jī)等場(chǎng)景。需要留出對(duì)應(yīng)接口,方便靈活切換。
審核編輯:劉清
-
嵌入式開(kāi)發(fā)
+關(guān)注
關(guān)注
18文章
1035瀏覽量
47719 -
上位機(jī)
+關(guān)注
關(guān)注
27文章
945瀏覽量
55009 -
linxu
+關(guān)注
關(guān)注
0文章
7瀏覽量
2576
原文標(biāo)題:嵌入式中,日志調(diào)試法的一些規(guī)則!
文章出處:【微信號(hào):麥克泰技術(shù),微信公眾號(hào):麥克泰技術(shù)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論