聊聊微信 Xlog

同步地址

本文介紹 MARS xlog 使用以及使用過程中踩過的坑

xlog 是什么

xlog 是微信開源框架 MARS 的一部分, 處理應用日志

微信的對 xlog 的介紹文檔--「微信終端跨平臺組件 mars 系列(一) - 高性能日志模塊xlog)

總結出來就是

xlog 方案總結

使用流式方式對單行日志進行壓縮,壓縮加密后寫進作為 log 中間 buffer的 mmap 中

雖然使用流式壓縮并沒有達到最理想的壓縮率,但和 mmap 一起使用能兼顧流暢性 完整性 容錯性 的前提下,83.7%的壓縮率也是能接受的。使用這個方案,除非 IO 損壞或者磁盤沒有可用空間,基本可以保證不會丟失任何一行日志。

一個優秀的日志模塊必須做到:

  • 不能把用戶的隱私信息打印到日志文件里,不能把日志明文打到日志文件里。
  • 不能影響程序的性能。最基本的保證是使用了日志不會導致程序卡頓。
  • 不能因為程序被系統殺掉,或者發生了 crash,crash 捕捉模塊沒有捕捉到導致部分時間點沒有日志, 要保證程序整個生命周期內都有日志。
  • 不能因為部分數據損壞就影響了整個日志文件,應該最小化數據損壞對日志文件的影響。

上面這幾點也即安全性 流暢性 完整性 容錯性, 它們之間存在著矛盾關系:

  • 如果直接寫文件會卡頓,但如果使用內存做中間 buffer 又可能丟日志
  • 如果不對日志內容進行壓縮會導致 IO 卡頓影響性能,但如果壓縮,部分損壞可能會影響整個壓縮塊,而且為了增大壓縮率集中壓縮又可能導致 CPU 短時間飆高。

mars 的日志模塊 xlog 就是在兼顧這四點的前提下做到:高性能高壓縮率、不丟失任何一行日志、避免系統卡頓和 CPU 波峰。

xlog 使用

MARS 的 GitHub 上介紹比較詳細,

xlog 背景知識

先跑起來一個 Demo 之后, 需要深入了解一下

mmap

認真分析mmap:是什么 為什么 怎么用

mmap 是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用read,write等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。

mmap.png

正如微信的介紹文章中所說的:

mmap 是使用邏輯內存對磁盤文件進行映射,中間只是進行映射沒有任何拷貝操作,避免了寫文件的數據拷貝。操作內存就相當于在操作文件,避免了內核空間和用戶空間的頻繁切換。

mmap幾乎和直接寫內存一樣的性能,而且 mmap 既不會丟日志,回寫時機對我們來說又基本可控。

System.loadLibrary()

Java中System.loadLibrary() 的執行過程

上文中有關于該方法的源碼分析, 總結來說

  1. 該方法用來加載 'xxx.so' 文件, 一些 native 方法的具體實現
  2. 該方法會從以下位置加載 so 文件: /vendor/lib, /system/lib, /data/app/com.xxxxx.xxx-1

so 文件

因為 Android 手機 CPU 架構的差異, 可能會有很多版本的 so 文件, 如果你是使用本地編譯 xlog 的, 你應該注意對應不同 CPU 架構編譯不同的 so 文件

本地編譯的 so 文件放在 src/jniLibs 目錄下, AS 可以自動編譯到 apk 中

xlog 踩坑

我的坑主要是因為 xposed 的原因, 剛開始 Demo 很順利, 接入到項目中問題就一個個的

couldn't find "libstlport_shared.so

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/io.communet.ichater-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libc++_shared.so"
        at java.lang.Runtime.loadLibrary(Runtime.java:385)
        at java.lang.System.loadLibrary(System.java:993)
        at io.communet.ichater.main.util.LogUtils.initXLog(LogUtils.java:38)
        at io.communet.ichater.wx.hook.WxHook.dealWx(WxHook.java:163)
        at io.communet.ichater.wx.hook.WxHook.access$000(WxHook.java:48)
        at io.communet.ichater.wx.hook.WxHook$1.afterHookedMethod(WxHook.java:152)
        at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:374)
        at android.content.ContextWrapper.attachBaseContext(<Xposed>)
        at android.app.Service.attach(Service.java:702)
        at android.app.ActivityThread.handleCreateService(ActivityThread.java:2759)
        at android.app.ActivityThread.access$1800(ActivityThread.java:151)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1386)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
        at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:107)

上文以及提到會在哪里加載 so 文件, 但是由于 xposed 的原因, Classloader 指向的文件為 /data/app/io.communet.ichater-2/base.apk, 不能找到指定的 so 文件, 所以需要指定絕對路徑

解決:

String nativeLibraryDir = getNativeLibraryDir(context);

System.load(nativeLibraryDir + "/libc++_shared.so");
System.load(nativeLibraryDir + "/libmarsxlog.so");
/**
 * 獲取本地支持庫
 */
private static String getNativeLibraryDir(Context context) throws PackageManager.NameNotFoundException {
    ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo("io.communet.ichater", 0);
    return applicationInfo.nativeLibraryDir;
}

日志存儲位置

微信有提到關于日志同步和異步兩種寫入方式以及日志文件的存儲位置

mode : 文件寫入模式,分異步和同步,變量定義見 Xlog.java 里 AppednerModeXX, Release版本一定要用 AppednerModeAsync, Debug 版本兩個都可以,但是使用 AppednerModeSync 可能會有卡頓。

cacheDir : 緩存目錄,當 logDir 不可寫時候會寫進這個目錄,可選項,不選用請給 "", 如若要給,建議給應用的 /data/data/packname/files/log 目錄。

logDir : 日志寫入目錄,請給單獨的目錄,除了日志文件不要把其他文件放入該目錄,不然可能會被日志的自動清理功能清理掉。

實際運行中發現, 當同步寫入時, 日志文件開始會被存放在 cacheDir, 一段時間后, 會被放到 logDir, 但是異步模式下, 文件一直放在 cacheDir, 即便調用 appenderFlush 方法, 日志會從 mmap 中寫入文件, 但是文件的位置還是在 cacheDir, 當然, 應用有讀寫 SDCard 的權限

解決:

該問題還未查明原因, 目前的解決方法是不給 cacheDir, 文件會被直接放到 logDir, 但是, 官方說如果不給 cacheDir, 可能出現 SIGBUS, 參見 issue#249

2019/4/17更新: 解決了, 說起來都慚愧, 還有一個參數

cacheDays : 一般情況下填0即可。非0表示會在 _cachedir 目錄下存放幾天的日志。

將該值設置為 0 即可, 之前以為這個值表示的是緩存日志保存的天數, 設置了 7, 實際上保留緩存日志的天數默認 10 天, 清理邏輯如下

每次啟動時會刪除過期文件,只保留十天內的日志文件(該值定義在appender.cc中的 kMaxLogAliveTime ),所以給 Xlog 的目錄請使用單獨目錄,防止誤刪其他文件。目前不會根據文件大小進行清理。如若想自定義清理邏輯請自行更改appender.cc中的 __del_timeout_file 函數。 #Android

couldn't find "xxx.so" is 32-bit instead of 64-bit

注意和上文中的那個 BUG 區分, 這里是因為用 32 位的 so 代替 64 位的 so 導致的

解決:

jniLibs 下面不要放 64 位的, 只放 32 的, 可以兼容

未完待續

還有坑的話繼續更新

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • title: App技術選型--日志框架 版 本 歷 史 日志對于開發來說是非常重要的,不管是調試數據查看、bug...
    海南雞閱讀 1,491評論 0 0
  • 微信Mars——xlog使用全解析 很多人問我微信的Mars到底有什么用,今天就告訴你其中一個最簡單的! 如約而至...
    eclipse_xu閱讀 23,130評論 8 26
  • title: App技術選型--日志框架--- **版 本 歷 史**| **版本** | **責任人** | *...
    海南雞閱讀 1,757評論 0 1
  • UNIX網絡編程第二卷進程間通信對mmap函數進行了說明。該函數主要用途有三個:1、將一個普通文件映射到內存中,通...
    宇文黎琴閱讀 3,537評論 0 4
  • 一、 設計理念 1.空間換時間 1)多級緩存,靜態化 客戶端頁面緩存(http header中包含Expires/...
    帥T閱讀 3,621評論 1 15