在程式撰寫過程中,有時候我們會希望輸出一些內部的資訊,例如某某變數值是多少、有沒有進入某某函式等等,讓 debug 有線索可循。很多人的做法是直接在程式碼當中插入 printf 或 cout,到正式 build 的時候再手動將這些資訊移除,這種做法只適用於小規模的程式,並且在 GUI 程式比較難用。比較巧妙一點的做法是將相關的功能用 macro 包裝,靠 NDEBUG 或類似的 flag 來決定是否輸出這些除錯資訊。我記得 VB6 有個類似的功能叫做 Debug.Print,正式建置程式的時候這些指令將會被編譯器忽略。

以前我的做法是把一些常用的 debug 和 assertion 功能用 macro 包裝好塞在一個標頭檔裡面,依照現實需求略做修改,通常這樣就已經很夠用了,所以未曾在此多留心。後來我在《Applied C++: Practical Techniques for Building Better Software》讀到了一種複雜許多的 debug output 方法,才知道原來小題也可以大作到這種地步。複雜帶來的是功能上的彈性,例如在書中介紹的機制只要切換一個叫做「Debug Sink」的組件,就可以將蒐集到的資訊全部倒到 console、檔案、訊息視窗甚至是網路。不過這些額外的好處還不夠吸引我,所以我還是繼續使用自製的 macro 工具。

還有另一類概念不太一樣的應用,著重在後端紀錄程式執行的不正常狀態,通常稱為 logging。當一個程式 release 的時候我們通常不希望浪費力氣輸出 debug 資訊,不過仍然有可能希望程式能夠記錄一些有價值的資訊供日後分析。在C++當中有內建一個 ostream 物件叫做 clog,預設將資料輸出至 stderr,不過基本上並沒有比用 cout 好到哪裡去。

兩種應用目的不太一樣,相同處在於由程式碼當中蒐集資訊然後在背景中儲存或輸出,所以兩者可以共用相同的基礎建設。一個好的 debug 或 logging 工具應該要有以下的特性:

1. 簡單,不要造成撰寫、維護額外的負擔。

2. 彈性,容易篩選欲輸出的內容,也很容易切換輸出的目的地,例如console、檔案、訊息視窗、網路

3. 效率,因為這些屬於與功能無關的額外工作,所以成本越低越好。最好要滿足C/C++的中心思想,不要花費在沒用到的東西上。

4. 支援多執行緒,例如多個執行緒可以同時寫入,或者是可以針對個別執行緒產生獨立輸出。

5. 容忍一些C++特有的問題,像是不會被全域物件建構、解構順序給打敗。

我最近 Survey 了一些相關的工具,比較值得一提的是

1. Boost.log (http://boost-log.sourceforge.net/libs/log/doc/html/index.html)

功能非常全面,支援大多數的需求。由官網的文件看來架構非常複雜,不過使用界面還算簡單,只是要先接受一些 template mata programming 的東西。

Boost.log 通過了 Boost 的同儕審查,但遲遲未收錄到 Boost 當中,所以要自己到他們的網站下載、編譯。另一位作者 John Torjo 提出了 Boost.log v2,提案並沒有被 Boost 採納。(John Torjo 設計了另一個 debug 工具叫 SMART ASSERT,也被Boost拒絕。)

2. glog (http://code.google.com/p/google-glog/)

google 的開發工具,在 debug 方面著墨甚多,很合乎我的需求。事實上我差不多把他的原始碼研究完,然後改寫到我自己的工具中。另一點也很有趣的是我一開始接觸的是 Chrome 當中的一部分,後來才知道有獨立的 glog 專案。

3. log4cpp (http://log4cpp.sourceforge.net/)

仿log4j設計,比較著重在logging方面,不合我的需求。可參考這裡的說明

http://www.ibm.com/developerworks/cn/linux/l-log4cpp/index.html

4. log4cxx 。類似前者。是 apache 下的東西,似乎依賴其他的 apache 基礎建設

http://logging.apache.org/log4cxx/index.html

Boost.log功能比較全面;如果要做 debug output,那麼 glog 是我的首選;若是一般的logging用途,上面四者應該都很好用。

arrow
arrow
    全站熱搜

    novus 發表在 痞客邦 留言(1) 人氣()