android日誌蒐集原理及方案比較
說明: 本文只討論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/80493