android日誌搜集原理及方案比較
- 2019 年 10 月 3 日
- 筆記
說明: 本文只討論Log日誌,而不是應用的埋點日誌。
Android 日誌架構
用一張圖來了解Android Log的架構:
這裡涉及到三個進程:
APP進程: 調用Log的介面打日誌,最終通過soctket通訊發送給Logd進程
Logd進程:有一個緩衝區用於存儲日誌(環形緩衝區,當滿時會衝掉舊的日誌)
Logcat進程:可以在adb shell中創建(可以創建多個),查看緩衝區中日誌的進程(Android Studio的logcat也是一個Logcat進程)。
環形緩衝區是一個邏輯上的循環隊列,寫者可以往裡面寫東西,而一旦有內容會通知等待隊列里的讀者們來讀取內容,否則等待隊列列處於阻塞狀態。 這就意味Logcat進程讀取也是阻塞形式的。
基於快取的日誌方案
普通應用
該方案會在系統的Log類上封裝一層,應用調用封裝層的日誌介面。封裝層將業務記得log快取到一個StringBuffer中,當量達到一定閾值後,再刷到文件中。到達一定條件上傳到服務端。
基於快取的日誌方案 對於普通應用:實現一套自己的Log,將每次打的日誌快取
系統應用
在應用中開啟一起Logcat進程,不斷的讀取Logd進程中的日誌到快取中,當日品質達到一定的閾值後再刷如文件。這種方案可以搜集到所有應用的日誌。
缺點:
1. 寫文件 + 加密 會出現cpu峰值 2.崩潰或者進程意外退出 快取中的日誌可能無法刷到文件中,關鍵崩潰資訊可能丟失。 3. 對於智慧設備中專門做一個日誌進程去搜集所有應用的日誌,這種方案其實是簡單可行的。
基於記憶體映射mmp的方案
mmp 原理:
記憶體映射,簡而言之就是將用戶空間的一段記憶體區域映射到內核空間,映射成功後,用戶對這段記憶體區域的修改可以直接反映到內核空間,同樣,內核空間對這段區域的修改也直接反映用戶空間。那麼對於內核空間<—->用戶空間兩者之間需要大量數據傳輸等操作的話效率是非常高的。
以下是一個把普遍文件映射到用戶空間的記憶體區域的示意圖。
系統層提供了具體的將用戶空間地址映射到內核空間的具體介面函數,這裡未作學習。
通過mmp讀取磁碟文件:
如果在拷貝數據時,發現物理記憶體不夠用,則會通過虛擬記憶體機制(swap)將暫時不用的物理頁面交換到硬碟上,上圖步驟4所示。這個過程也與記憶體映射無關。
通過系統read/write文件原理:
它首先將文件內容從硬碟拷貝到內核空間的一個緩衝區,如圖過程1,然後再將這些數據拷貝到用戶空間,如圖過程2,在這個過程中,實際上完成了 兩次數據拷貝 ;
而mmap()也是系統調用,mmap()中沒有進行數據拷貝,真正的數據拷貝是在缺頁中斷處理時進行的,由於mmap()將文件直接映射到用戶空間,所以中斷處理函數根據這個映射關係,直接將文件從硬碟拷貝到用戶空間,只進行了 一次數據拷貝 。因此,記憶體映射的效率要比read/write效率高。
mmp作為日誌方案優勢
1.讀寫文件比普通文件操作效率更高 2.不會丟日誌(進程退出時能刷日誌到映射的地址中) 會寫日誌的時機: 記憶體不足 進程退出 調用 msync 或者 munmap 不設置 MAP_NOSYNC 情況下 30s-60s(僅限FreeBSD) 3. 對於CPU峰值問題,參考微信XLOG解決方案如下: 追加每行日誌時,先壓縮後加密(避免了對整個文件的壓縮/加密)
思考:
大多數用戶的日誌時無用的,日誌上傳場景考慮,通過指令撈取
具體日誌策略需要綜合多方面考慮: 流暢性/完整性/容錯性/安全性
MMP的具體使用還要結合具體場景,需要測試追加日誌大小
參考:
https://blog.csdn.net/tencent_bugly/article/details/53157830
http://ju.outofmemory.cn/entry/224106
https://blog.csdn.net/coolwriter/article/details/80493166