楊善寧
摘要:日志功能被廣泛應(yīng)用于各種軟件開(kāi)發(fā)領(lǐng)域,尤其是在嵌入式系統(tǒng),然而提高效率、減少開(kāi)銷(xiāo),一直是日志系統(tǒng)的所追求的目標(biāo)和所面臨的挑戰(zhàn)。文中介紹了一個(gè)輕量高效、易于跨平臺(tái)的日志系統(tǒng)的設(shè)計(jì)思路與實(shí)現(xiàn)要點(diǎn),并通過(guò)基準(zhǔn)對(duì)比測(cè)試,展示了其在效率和性能上的表現(xiàn)。
關(guān)鍵詞:日志系統(tǒng);嵌入式;輕量;高效;跨平臺(tái)
中圖分類(lèi)號(hào):TP311.5 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2017)28-0077-02
Abstract: Logging functionality is widely used in various software development areas, especially, the embedded system. Nevertheless, increasing efficiency and reducing overhead are always the goals that a logging system pursues and the challenges to what it faces as well. This paper represents the design thoughts and implementation techniques of a lightweight, high-efficient and cross-platform logging system, and illustrates the logging efficiency and performance through benchmark test.
Key words: logging system; embedded; lightweight; high-efficient; cross-platform
1 概述
規(guī)范與齊全的日志是衡量一個(gè)軟件系統(tǒng)質(zhì)量的重要指標(biāo),也是大型軟件系統(tǒng),尤其是嵌入式系統(tǒng)進(jìn)行離線分析診斷問(wèn)題的重要途徑。目前,市場(chǎng)上存在著不少優(yōu)秀的開(kāi)源日志系統(tǒng),例如,使用比較廣泛的有Apache log4cxx,Google logging (Glog)等,但這類(lèi)開(kāi)源軟件的框架通常過(guò)于龐大復(fù)雜,不便于團(tuán)隊(duì)統(tǒng)一規(guī)范使用,也不易于跨硬件平臺(tái)進(jìn)行移植;或因兼顧編程開(kāi)發(fā)語(yǔ)言、系統(tǒng)平臺(tái)等因素而引入一些額外的開(kāi)銷(xiāo),從而導(dǎo)致在性能與效率上有所損失。
在整個(gè)軟件系統(tǒng)中,日志系統(tǒng)本質(zhì)上是起輔助性作用的,所以,應(yīng)盡可能減少其系統(tǒng)開(kāi)銷(xiāo),而提高其效率和吞吐量。尤其在嵌入式開(kāi)發(fā)領(lǐng)域,日志系統(tǒng)的簡(jiǎn)潔高效性是一個(gè)極為重要的軟件質(zhì)量指標(biāo)。除了這里提到的程序代碼的簡(jiǎn)潔性與高性能的追求外,在嵌入式開(kāi)發(fā)中,為了確保在不同系統(tǒng)平臺(tái)上獲得一致的日志操作體驗(yàn),同時(shí)也便于一些基于日志的監(jiān)測(cè)與測(cè)量分析系統(tǒng)的集成,還需要適當(dāng)考慮跨平臺(tái)的可移植性與可擴(kuò)展性。
通過(guò)以上分析,并結(jié)合相關(guān)開(kāi)源日志系統(tǒng)的實(shí)現(xiàn)機(jī)制的研究,去掉不必要的功能特性和避免一些不優(yōu)化的實(shí)現(xiàn)方式,從簡(jiǎn)單易用性、效率和性能方面出發(fā),設(shè)計(jì)并實(shí)現(xiàn)一套簡(jiǎn)潔易維護(hù)、高效率高性能的跨平臺(tái)日志系統(tǒng)。
2 系統(tǒng)功能簡(jiǎn)介
設(shè)計(jì)與開(kāi)發(fā)的日志系統(tǒng)稱為Alog,主要以簡(jiǎn)單易用性、高效性、跨平臺(tái)可移植性為核心目標(biāo),著重為嵌入式軟件項(xiàng)目與開(kāi)發(fā)團(tuán)隊(duì)提供有效統(tǒng)一的日志操作體驗(yàn)。Alog日志系統(tǒng)包括的主要功能特性有:
1) 根據(jù)標(biāo)簽、嚴(yán)重級(jí)別來(lái)分類(lèi)寫(xiě)日志;
2) 日志輸出到控制臺(tái)、文件系統(tǒng)、Android logcat;
3) 使用配置文件來(lái)控制寫(xiě)日志的行為;
4) 提供豐富的宏定義以便于寫(xiě)入特定格式的日志用于監(jiān)測(cè)與測(cè)量分析;
5) 支持x86、ARM、Android平臺(tái)。
Alog使用C語(yǔ)言printf函數(shù)風(fēng)格的日志函數(shù)設(shè)計(jì),之所以選擇這樣的設(shè)計(jì),而不是使用C++輸入輸出流風(fēng)格或C#控制臺(tái)輸出樣式,是因?yàn)榭紤]到目前在嵌入式軟件項(xiàng)目中,軟件大多是使用C/C++編寫(xiě)的,通過(guò)使用Alog提供的相關(guān)宏定義,方便快捷地替換原有日志函數(shù)調(diào)用,從而使Alog易用性和使用范圍得到提高。
用戶可通過(guò)配置文件來(lái)設(shè)定日志按標(biāo)簽、嚴(yán)重性來(lái)決定是否輸出,以及輸出到控制臺(tái)或文件等。同時(shí),Alog提供宏以控制輸出為特定格式的日志,便于基于日志的腳本或軟件進(jìn)行監(jiān)測(cè)與測(cè)量等用途。此外,在嵌入式軟件開(kāi)發(fā)中,ARM架構(gòu)及l(fā)inux、android系統(tǒng)是極為普遍的,因此,Alog優(yōu)先提供這方面的跨平臺(tái)支持。
3 系統(tǒng)設(shè)計(jì)
Alog的首要設(shè)計(jì)目標(biāo)是精簡(jiǎn)輕量、高效高性能,去掉不實(shí)用的特性,保留最有價(jià)值的功能,從而使得邏輯簡(jiǎn)單清晰,不易出錯(cuò),并且代碼執(zhí)行效率高,使得更適用于嵌入式系統(tǒng)的開(kāi)發(fā)。
3.1 功能模塊設(shè)計(jì)
Alog的功能模塊主要包括API接口層、日志操作主控邏輯、配置文件解析和輸出模塊,其中輸出模塊按照日志輸出目的地不同細(xì)分為終端屏幕、文件系統(tǒng)和Android logcat。如下圖1簡(jiǎn)要描述了Alog的功能模塊組成。
API接口層主要負(fù)責(zé)屏蔽內(nèi)部細(xì)節(jié),給上層應(yīng)用程序提供訪問(wèn)接口,有利于統(tǒng)一規(guī)范地使用日志系統(tǒng),主要接口包括初始化、關(guān)閉日志系統(tǒng)、寫(xiě)日志、查看運(yùn)行狀況等,并以C語(yǔ)言宏定義的方式提供常規(guī)與特殊用途的日志功能。
Alog配置文件的解析與應(yīng)用,使到用戶可方便靈活地控制日志的行為:
1) 設(shè)置是否打印日志到控制臺(tái)屏幕、文件、Android logcat;
2) 設(shè)置日志保存路徑、文件名等;
3) 設(shè)置默認(rèn)日志輸出級(jí)別,也可設(shè)置特定標(biāo)簽、特定嚴(yán)重級(jí)別的日志輸出等。
日志主控模塊負(fù)責(zé)日志的操作行為,實(shí)現(xiàn)控制邏輯,格式化日志文本。根據(jù)日志中指定的標(biāo)簽,使用哈希的方法檢索相應(yīng)配置,快速確定日志的操作行為。endprint
日志輸出模塊將格式化好的日志,輸出到特定的目的地,如磁盤(pán)文件、屏幕控制臺(tái)等。使用C++面向?qū)ο笤O(shè)計(jì),以繼承的方式實(shí)現(xiàn)基類(lèi)聲明的接口,這樣可以更好的復(fù)用主控模塊的控制邏輯,只需實(shí)現(xiàn)特定的輸出邏輯即可。
3.2 接口設(shè)計(jì)
Alog使用C/C++編程語(yǔ)言進(jìn)行開(kāi)發(fā),以得到良好的運(yùn)行效率和性能,同時(shí),以動(dòng)態(tài)庫(kù)與靜態(tài)庫(kù)兩種形式對(duì)外提供接口,方便用戶靈活使用。為了進(jìn)一步屏蔽瑣碎的細(xì)節(jié),Alog提供C語(yǔ)言宏定義以供外部訪問(wèn)。其訪問(wèn)接口主要有兩大類(lèi):一類(lèi)是用于輸出常規(guī)的日志,如輸出特定標(biāo)簽及特定嚴(yán)重性級(jí)別的日志;一類(lèi)是用于輸出特定格式的日志,以便使用腳本或軟件對(duì)日志進(jìn)行掃描分析,進(jìn)行實(shí)時(shí)監(jiān)測(cè)與性能參數(shù)測(cè)量等。
4 系統(tǒng)實(shí)現(xiàn)
4.1 判斷是否輸出日志
Alog基于標(biāo)簽與嚴(yán)重級(jí)別來(lái)輸出日志,實(shí)現(xiàn)過(guò)程中,使用C++標(biāo)準(zhǔn)庫(kù)的std::map來(lái)關(guān)聯(lián)標(biāo)簽與相應(yīng)的日志操作行為設(shè)置,這樣也是為了能夠在運(yùn)行時(shí)動(dòng)態(tài)添加標(biāo)簽配置項(xiàng)。C++標(biāo)準(zhǔn)庫(kù)的std::map內(nèi)部實(shí)現(xiàn)使用的是哈希算法,其查找、插入操作的復(fù)雜度均為O(n),具備理想的運(yùn)行時(shí)效。首先,由配置文件解析模塊在程序開(kāi)始運(yùn)行時(shí),解析并應(yīng)用Alog配置,即初始化特定標(biāo)簽的輸出日志的級(jí)別。然后,在運(yùn)行時(shí),根據(jù)標(biāo)簽名在該std::map中查找,如果不存在相應(yīng)的配置項(xiàng),則插入默認(rèn)級(jí)別的配置項(xiàng),否則,使用查找到的配置項(xiàng)。最后,比較標(biāo)簽所配置的輸出級(jí)別與日志請(qǐng)求的級(jí)別,決定是否輸出日志,具體流程如下圖2所示。
4.2 格式化日志文本
Alog的日志由消息頭與消息體兩部分組成。消息頭的格式是固定的,其包含的字段依次是:日期時(shí)間,嚴(yán)重級(jí)別,標(biāo)簽名,文件名,代碼行號(hào)。消息體為用戶指定要輸出的日志消息內(nèi)容。此外,Alog為支持基于日志進(jìn)行監(jiān)測(cè)與測(cè)量,提供稍微特別的日志格式,其消息頭與普通日志相同,僅在消息體前面,使用固定格式的花括弧號(hào),將用戶指定的日志數(shù)據(jù)包裝起來(lái)。借助于一些腳本或軟件,用戶可以方便地將這些數(shù)據(jù)進(jìn)行繪圖并加以展示,然后進(jìn)行直觀地分析與評(píng)測(cè),從而了解系統(tǒng)的運(yùn)行狀況和變化趨勢(shì)。
為提高效率,Alog在格式化日志消息時(shí),代碼實(shí)現(xiàn)上,使用棧存儲(chǔ)空間,而不是從系統(tǒng)堆中動(dòng)態(tài)分配內(nèi)存。很多日志系統(tǒng)使用從堆上動(dòng)態(tài)分配內(nèi)存的策略,如Glog就是這樣實(shí)現(xiàn)的。雖然,從堆上分配存儲(chǔ)可以讓用戶輸出任意長(zhǎng)度的日志,但它的效率比不上從??臻g直接分配,而且,系統(tǒng)的日志通常不會(huì)太長(zhǎng)。相比之下,Alog采用的策略一是從程序棧上分配存儲(chǔ)空間;二是限制日志長(zhǎng)度為256字節(jié),這通常已經(jīng)足夠使用,如果不夠,用戶可以寫(xiě)兩條日志,而這是極少發(fā)生的情況。
4.3 輸出日志
Alog在輸出日志時(shí),根據(jù)配置文件來(lái)決定日志輸出的目的地,支持輸出到屏幕控制臺(tái)、文件、Android logcat。實(shí)現(xiàn)時(shí),使用C++繼承與多態(tài)特性,在父類(lèi)中實(shí)現(xiàn)公共可復(fù)用的代碼邏輯,而子類(lèi)僅需實(shí)現(xiàn)各自特有的部分,并提供必要的接口實(shí)現(xiàn)即可。對(duì)于屏幕控制臺(tái),使用標(biāo)準(zhǔn)錯(cuò)誤stderr,這是因?yàn)閟tderr是不進(jìn)行緩存處理的,可以將日志直接輸出到屏幕以確保正確的順序;對(duì)于輸出到日志文件,具體實(shí)現(xiàn)時(shí),使用POSIX兼容的標(biāo)準(zhǔn)文件讀寫(xiě)接口將日志寫(xiě)入磁盤(pán);對(duì)于Android平臺(tái),調(diào)用其提供的日志輔助函數(shù),將日志輸出到Android logcat。如下圖3簡(jiǎn)要說(shuō)明日志輸出的類(lèi)設(shè)計(jì)。
5 性能對(duì)比
日志系統(tǒng)本身不是業(yè)務(wù)的重點(diǎn),因此,應(yīng)該以更少的代價(jià)來(lái)實(shí)現(xiàn)更多的價(jià)值,即提供便利而不會(huì)帶來(lái)過(guò)多的系統(tǒng)開(kāi)銷(xiāo)。無(wú)論在設(shè)計(jì)上還是在實(shí)現(xiàn)中,Alog始終以簡(jiǎn)潔與高效,并具備必要的跨平臺(tái)特性為目標(biāo),保持簡(jiǎn)單清晰的功能邏輯,運(yùn)用高效的技術(shù)實(shí)現(xiàn)細(xì)節(jié),從而成為更適合嵌入式開(kāi)發(fā)的日志系統(tǒng)。
為測(cè)試Alog的性能,將Google的開(kāi)源日志系統(tǒng)Glog與Alog進(jìn)行對(duì)比測(cè)試。測(cè)試環(huán)境使用操作系統(tǒng)為linux 3.18,CPU為Qualcomm Snapdragon 820,內(nèi)存為2GB的DDR3,外部存儲(chǔ)為32GB的Flash。測(cè)試用例為使用Glog與Alog分別寫(xiě)入1000000條特定長(zhǎng)度的日志到文件,然后統(tǒng)計(jì)寫(xiě)入每種長(zhǎng)度的日志所花費(fèi)的時(shí)間。如下圖4,展示了Glog與Alog性能對(duì)比情況:
6 結(jié)束語(yǔ)
通過(guò)在功能上進(jìn)行精簡(jiǎn)設(shè)計(jì),以及在性能上進(jìn)行優(yōu)化實(shí)現(xiàn),開(kāi)發(fā)出一個(gè)輕量而高效,易于跨平臺(tái)的日志系統(tǒng),能夠被廣泛地應(yīng)用到各領(lǐng)域的軟件開(kāi)發(fā),尤其是嵌入式軟件系統(tǒng)的開(kāi)發(fā)。
參考文獻(xiàn):
[1] 李英軍.設(shè)計(jì)模式: 可復(fù)用面向?qū)ο筌浖幕A(chǔ)[M].北京: 機(jī)械工業(yè)出版社,2000:84-88.
[2] 侯捷. C++標(biāo)準(zhǔn)庫(kù)[M].2版.北京: 電子工業(yè)出版社,2015.
[3] 黃藝海,胡君.日志審計(jì)系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程,2006,33(22):67-68.
[4] 劉思堯,李斌.基于ELK 的電力信息監(jiān)控日志審計(jì)系統(tǒng)實(shí)現(xiàn)[J].電腦知識(shí)與技術(shù),2016, 12(30):61-64.
[5] 孫李斌,趙明明. 基于Linux的嵌入式日志系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J].電子科學(xué)技術(shù), 2017, 4 (3):97-99.
[6] google/glog. Github[EB/OL]. https://github.com/google/glog.endprint