設計log函式庫的幾個要點

李先靜發表於2020-04-06

 

只要留意一下大專案的原始碼,你會發現,幾乎無一例外的包括一個log模組。它的功能很直觀:記錄一些程式執行時資訊,多數情況是用來輔助debug的。大專案都有一套的log的函式,在它的基礎上開發,呼叫它提供的Log函式就行了,比如linux核心、apache等。也有開源log函式庫,可以直接拿過用。這裡,我們並不鼓勵重新發明輪子,但在少數情況下,確實不得不編寫自己的log函式。下面是對以前的經驗的總結,和大家交流一下。

 

1.         按重要程度過濾log。在除錯程式時,當然希望有較多的除錯資訊,能夠為我們分析提供幫助,但使用太多Log是有代價的,它不但要佔用空間,還要佔用執行時間。我們不希望在Release版本中有太多的Log資訊,那會浪費使用者的資源。通常的做法是,把Log資訊按重要程度分成不同的種類,在不同的情況下,列印不同種類的資訊。錯誤的種類,一般分為嚴重錯誤、錯誤、警告、除錯等幾個級別。

 

2.         按模組過濾Log。對於大的專案的,可能由數十個甚至上百個模組組成。完成一個複雜的任務,需要在不同模組間切換好幾次,得到的Log資訊比較龐雜。多數情況下,我們的注意力,都放在幾個容易出錯的焦點模組上,Log資訊太雜,要找出焦點模組中的Log會比較累,輸出無用的Log也會增加系統的開銷。這時,我們可以按模組過濾,只留下所關注模組的Log。可以設定一個過濾掩碼(mask),這個模組佔用一位,置1的模組表示打Log開關。

 

3.         Log的格式。Log的格式最好能夠統一起來,讓人感覺比較舒服,檢視時也有個好的心情。同時最好能與偵錯程式配合起來,比如,在VC中,若按檔名(行號): 資訊的格式輸出,雙擊該資訊,VC自動跳到列印該Log的程式碼位置。

 

4.         Log的內容。Log的內容並不無固定規則,一般來說,Log提供下列資訊,對除錯會有一些幫助:

a)         模組名。

b)        列印該Log的位置,如檔名、行號、函式名等。

c)        列印該Log的時間。

d)        對由多個模組組成的專案,若這些模組又並不同步釋出時,版本不匹配會引發一些問題,這就有必要列印出各模組的build時間或者版本資訊。

 

5.         能重定向log的內容。常見的做法是把log資訊列印到螢幕上,這也不盡然,特別對於非PC平臺的情況,有的輸出到串列埠,有的儲存到檔案,有的輸出到socket,輸出的目標多種多樣。所以,在設計一個通用的log函式庫時,最好考慮到這些需求,抽象出一套輸出介面是較為理想的做法。

 

6.         動態配置Log。若每次配置Log的規則,都要重新編譯程式,這常常是不能接受的。在設計時要考慮提供動態配置功能。動態配置的方法有多種,可以通過命令列引數,可以通過環境變數,可以通過配置檔案,也可以提供一個設定介面,這要根據具體的情況而定。配置的內容常常包括:過濾級別、模組掩碼、輸出格式和輸出目標等。

 

7.         常用的巨集。在C語言中,有幾個巨集,可能對於編寫Log函式庫有用處:

 

a)         __FILE__ 當前檔名。

b)        __LINE__ 當前行號。

c)        __func__ 當前函式,好像新標準才支援。

d)        __DATE__ 編譯日期。

e)         __TIME__ 編譯時間。

 

8.         引數可變。一般來說,Log函式的引數都是可以變化的,這很容易實現,C語言支援引數個數可變的函式。有時,為了方便,會定義一些巨集包裝一下Log函式,可往往不太走運,因為C語言新標準裡才支援引數可變的巨集,目前常用的gcc版本都支援,而VC這個冤大頭卻不支援。若非要使用變參巨集,一定要考慮可以移植性問題。

 

 

相關文章