天天看點

C++ 日志架構

何為日志架構

日志架構:一個經過專門設計的實用程式,用于規範應用程式的日志記錄過程。

日志架構可以自己編寫(技術要牛才行哦),也可以由第三方(例如:log4cplus)提供。對于不同的日志架構,各自的組織在實作方式上也有所不同。

雖然可以簡單地“标準化”日志(例如:調用檔案系統 API,将資訊寫入名為 log.txt 的檔案),但是要成為一個嚴格意義上的架構,必須要超越标準化。也就是說,日志架構必須通過處理日志記錄來标準化解決方案,進而暴露一個标準的 API。

沒明白?那就再具體一些,設想一個日志架構,封裝了三個主要部分:

C++ 日志架構

當想要捕獲程式的運作時資訊時,首先要發出要記錄的資訊。然後,格式化這些資訊。最後,決定将它輸出到哪裡。一般情況下,會輸出到檔案中,但是也可以将其輸出到控制台、資料庫,或者任何能夠接收資料的地方。

如果有一系列代碼,能夠解決這些問題,那麼就可以被看作是一個日志架構。

為什麼不是 cout

使用日志,隻為成為更好的攻城獅。

也許有人會問:既然 C++ 中有 cout,為什麼還要使用日志呢?

無法否認,在使用像 C++、Java、PHP 這樣的程式設計語言時,我們會經常将消息列印到控制台,因為這是開發、測試和調試程式的一部分。但倘若我們正在處理一個服務端程式,卻無法看到其内部發生了什麼,這時該怎麼辦?唯一的可見性工具是日志檔案,如果沒有日志,我們就不能進行任何調試,也無法知道程式内部在做什麼。

盡管 C++ 中有相當友善的 cout 輸出流,可以在控制台上列印一些資訊,或者可以通過其他方式将這些資訊重定向到檔案中,但這對于實際的應用程式來說根本不夠。尤其對于複雜的 C++ 程式來說,像 log4cplus 或任何其他日志架構能夠提供了更多的靈活性,而這是 cout 不可能完成的。

在編寫代碼時,使用日志架構是一種很好的實踐。即使像《代碼整潔之道》這樣的書籍,也建議學習像 Log4j 這樣的架構進行日志記錄。是以,請盡可能的在生産代碼中使用日志,而不是用 cout 來列印東西(這是不可接受的)。

使用日志的好處

日志是一個優秀系統不可或缺的組成部分。

對于很多人來說,日志的作用僅限于調試。其實不然,它在很多方面都非常有用:

  • 日志是最好的的診斷工具

絕大多數人都曾面臨這樣的困境——一旦程式出現問題,很長時間都找不出原因!

缺少日志,我們将不得不依賴于客戶或支援團隊,讓他們描述在什麼情況下發生了什麼(很可能會存在一些誤導)。随後我們需要通過開發環境重制問題,并進行各種調試,直至錯誤修複為止,然而這一般會耗費很長時間。但若有日志的幫助,我們便能迅速擺脫這種困境,可以很快地發現異常,并快速定位、解決問題!

  • 日志讓我們有機會檢測子產品的瓶頸

随着項目規模的增加,子產品會越來越多,調優也變成了一場持久戰。

通過記錄某些操作的日期和時間,我們可以及時地檢測子產品的瓶頸,并針對性地對一些耗時操作做出優化。

  • 日志有助于我們了解使用者行為

為了提高産品品質,提供個性化服務,就必須了解使用者行為——他們做了什麼,想要什麼。

要搞清楚這些,當然要有資料,是以需要采集和分析使用者的行為,而日志無疑是最主要的資料來源。

要不要重新發明輪子

不要去重新發明輪子——《麥肯錫方法》
C++ 日志架構

既然已經對日志架構有了明确的了解,那麼應該使用現有的日志架構,還是建構自己的日志架構呢?其實,這是一個老生常談的問題了——要不要重新發明輪子?引用莎士比亞戲劇《哈姆雷特》中的一句名言:

To be or not to be - that is the question.

現在我們正處于技術大爆發的時代,每一個技術領域中都有很多好的解決方案。是以,自己完全不需要、也不應該去寫日志架構。就像不應該寫版本控制工具或 Bug 跟蹤管理工具一樣,其他人已經把這些東西搞出來了,而且搞的很好,Git、SVN,Bugzilla、Trac……應有盡有,我們完全可以花很少的錢,甚至是免費使用它們。

是以,請避免重複勞動,不要去重新發明輪子。應該堅持在自己的領域解決問題,将時間花在刀刃上。話雖如此,但我們還是需要了解關于輪子的一些細節(誰造的?怎麼創造的?如何使用?),以從中接受靈感,并把自己的知識加進去。

是以,當需要一個日志架構時,應該使用現有的架構,而不是去重新發明輪子。那麼,問題來了,日志架構都有哪些呢?

日志架構都有哪些

C++ 中的日志架構有很多,其中比較著名的有:

  • log4cxx:Java 社群著名的 Log4j 的 C++ 移植版,用于為 C++ 程式提供日志功能,以便開發者對目标程式進行調試和審計。
  • log4cplus:一個簡單易用的 C++ 日志記錄 API,它提供了對日志管理和配置的線程安全、靈活和任意粒度控制(也基于 Log4j)。
  • Log4cpp:一個 C++ 類庫,可以靈活地記錄到檔案、syslog、IDSA 和其他目的地(也基于 Log4j)。
  • google-glog:一個 C++ 語言的應用級日志記錄架構,提供了 C++ 風格的流操作和各種輔助宏。
  • Pantheios:一個類型安全、高效、泛型和可擴充性的 C++ 日志 API 庫(号稱 C++ 領域速度最快的日志庫)。
  • POCO:還提供了一個 好的日志支援文檔。
  • ACE:ACE 也有日志支援。
  • Boost.Log:設計的非常子產品化,并且可擴充。
  • Easylogging++:輕量級高性能 C++ 日志庫(隻有一個頭檔案)。
  • G3log:一個開源、支援跨平台的異步 C++ 日志架構,支援自定義日志格式。基于 g2log 建構,提升了性能,支援自定義格式。
  • Plog:可移植、簡單和可擴充的 C++ 日志庫。
  • spdlog:一個快速的 C++ 日志庫,隻包含頭檔案,相容 C++11。
  • ……

這麼多架構,應該選擇哪一個呢?

由于每個人的需求和技術棧都不一樣,是以很難直接回答這個問題,但是有一些選擇标準可供參考。

日志選擇标準

  • 易用性
易于使用的架構,能讓你事半功倍。

易用性,是優秀架構的一個重要特性。是以無論使用什麼架構,都應優先考慮這一點。

對于日志架構而言,一旦被標明,在後期開發過程中,項目組中的每個人都會頻繁使用。如果易用性不好的話,那絕對是一個噩夢!是以,在選擇日志架構時,應盡量找那些由簡單、直覺的 API 實作的方案。一個簡單日志架構,衡量标準可參考:對于缺乏經驗的團隊成員,應該在檢視文檔和簡單示例之後,就能夠快速上手。

  • 性能(效率)
功能決定現在,性能決定未來。

另一個要考慮的重要因素是性能影響。正如上面提到的,我們會經常調用日志,這可能會對程式的性能産生巨大的影響。

想象一下,一個日志架構,需要花費很長的時間才能啟動,在每次調用時阻塞并執行檔案 I/O,缺少緩沖機制……對于這樣的架構,你會用嗎?

是以,在評估日志架構時,可以參考網上的一些文章來比較,也可以自己做一些比較性實驗(基準測試),例如:吞吐量——測量每秒可以完成多少次方法調用(越高越好);采樣——測量每次調用執行究竟花費了多少時間(越低越好)。

  • 對現有代碼的影響
影響越小,越容易維護。

在以後的使用中,日志将無處不在。就像會影響運作時性能一樣,它們也會影響源碼的可維護性。

從應用程式的角度來看,日志所處的位置比較尴尬。之是以這麼說,是因為我們盡力隔離依賴性,提供良好的接口,并最小化耦合,在程式設計時考慮的是單一職責原則。然後日志出現了,它到處都是,與周圍的代碼無關。與這些優秀的設計原則相比,日志顯得有些背道而馳。

  • 社群支援
每一個成功架構的背後,都有一個偉大的社群。

架構的生命力源于不斷地完善和發展,如果沒有強大的社群做支撐,這個架構便失去了源動力。

是以,在選擇架構時,這一點非常重要——所選的架構是否有專門的團隊做支撐?在像 Stack Overflow 這樣的問答網站上,它是否有很強的存在感?確定一點,如果在使用過程中遇到了問題,你能有辦法快速解決。倘若選擇了一個不知名的架構,當遇到了 Bug 時,那麼可能會浪費大量的時間來解決問題。

  • 完整性
完整的架構,鑄就完美的生産力。

在最前面,我們将日志的功能分為三個主要部分:日志記錄、格式化和輸出地,是以要確定所選的日志架構徹底解決了這些問題。

日志記錄和輸出地比較基礎,幾乎所有日志架構都有這些概念。話雖如此,但對于好的架構來說,應該巧妙地将日志記錄與輸出地分開,并且還應該有多種可選的輸出地。在理想情況下,最好能夠自定義輸出地。

一般情況下,格式化日志檔案會整齊地排列,并具有很好的可讀性。但在 DevOps 的世界裡,這些遠遠不夠。具體來說,日志檔案需要被格式化為可解析的資料。通過将日志輸出作為資料處理,可以很容易地聚合、搜尋和可視化日志,進而能夠在生産支援方面助你一臂之力。是以,要確定日志架構擁有這種能力。

  • 發展前景
隻有前途光明,方能大行其道。

繼續閱讀