title: App技術選型--日志框架
版 本 歷 史
版本 | 責任人 | 日期 | 備注 |
---|---|---|---|
V1.0 | 曾維銘 | 2017-04-12 | 創(chuàng)建文檔蝉揍。 |
日志對于開發(fā)來說是非常重要的,不管是調(diào)試數(shù)據(jù)查看盹牧、bug問題追蹤定位钞瀑、數(shù)據(jù)信息收集統(tǒng)計沈撞,日常工作運行維護等等,都大量的使用到雕什。
功能需求
- 線程的信息
- 類的信息
- 方法的信息
- 格式打印JSON缠俺、XML等
- 點擊鏈接跳轉(zhuǎn)到源碼打印處
- 擁有默認TAG和自定義TAG
- release包中不能泄漏Log
- 使用友好,使用高效
- 日志持久化到本地
- 日志框架的擴展性
Xlog
mars 是微信官方的終端基礎組件贷岸,是一個使用C編寫的業(yè)務性無關壹士,平臺性無關的基礎組件。Xlog是mars中可以獨立使用的日志模塊偿警。
優(yōu)勢:
- 性能好:使用了中間層躏救,減少了讀寫磁盤的次數(shù)。使用mmap進行邏輯內(nèi)存對磁盤文件進行映射螟蒸,中間只是進行映射沒有任何拷貝操作盒使,避免了寫文件的數(shù)據(jù)拷貝,操作內(nèi)存就相當于在操作文件七嫌,避免了內(nèi)核空間和用戶空間的頻繁切換少办。占用內(nèi)存CPU資源少。
- 功能豐富:與原生Log使用幾乎一致诵原,但增加了寫入文件功能英妓,同時自帶加密
- 穩(wěn)定:騰訊微信團隊正在使用,久經(jīng)考驗皮假。
面臨的問題:
- Xlog是用C寫的,出問題調(diào)試起來不太友好骂维。
- so庫比較大惹资,導入后APK增大1.5M。
解決方案:
- 只能通過 xlog 輸出的信息進行排查航闺。不過日志作為輔助系統(tǒng)褪测,出問題可能性低,而且問題影響不大潦刃。
- 如果很在乎APK包大小的話侮措,可以只集成armeabi的so包。
持久化的實現(xiàn)
為了提高日志的性能乖杠,Xlog引入了 mmap作為中間buff層分扎,當buff層滿足一定條件時,才將日志寫到存儲空間胧洒。
日志存儲位置
初始化時畏吓,寫在logPath中墨状。
logPath = Environment.getExternalStorageDirectory().getAbsolutePath()/sdcard/PhiComm/app name/logs
日志文件命名
APP名_日期
日志格式
一般內(nèi)容:[日志級別][日期][PID][TAG(類名)][線程---日志內(nèi)容]
方法棧:[日志級別][日期][PID][TAG(類名)][線程---方法棧]
日志使用策略
每次啟動時會刪除過期文件,只保留十天內(nèi)的日志文件(該值定義在appender.cc中的 kMaxLogAliveTime )菲饼,所以給 Xlog 的目錄請使用單獨目錄肾砂,防止誤刪其他文件。目前不會根據(jù)文件大小進行清理宏悦。如若想自定義清理邏輯請自行更改appender.cc中的 __del_timeout_file 函數(shù)镐确。
日志使用級別
<table><tr><th></th><th colspan="2">debug</th><th colspan="2">release</th></tr><tr><td></td><td>控制臺</td><td>持久化</td><td>控制臺</td><td>持久化</td></tr><tr><td>v</td><td>程序說明</td><td>null</td><td>null</td><td>程序說明</td></tr><tr><td>d</td><td>需要調(diào)試的代碼</td><td>null</td><td>null</td><td>null</td></tr><tr><td>i</td><td>程序正常運行時日志</td><td>程序正常運行時日志</td><td>null</td><td>程序正常運行時日志</td></tr><tr><td>w</td><td>會出現(xiàn)潛在錯誤的情形</td><td>會出現(xiàn)潛在錯誤的情形</td><td>null</td><td>會出現(xiàn)潛在錯誤的情形</td></tr><tr><td>e</td><td>catch塊中,程序狀態(tài)檢查語句</td><td>catch塊中饼煞,程序狀態(tài)檢查語句</td><td>null</td><td>catch塊中源葫,程序狀態(tài)檢查語句</td></tr></table>
日志混淆問題
類名,方法名等參數(shù)使用的是Java lang包下的StackTraceElement和Throwable獲得派哲。具體混淆策略需要在原型中測試后才能確定臼氨。
LogUtils
由于Xlog提供的功能有限,為了滿足使用需求芭届,這里對Xlog進行了封裝储矩。
實現(xiàn)的功能:
- 支持打印字符串,集合褂乍,JSON持隧,日志級別,日期逃片,線程ID屡拨,線程名,異常信息褥实,堆棧信息呀狼,源代碼跳轉(zhuǎn)。
- 日志持久化到外部存儲损离,自動清理過期日志哥艇,保存最近十天的日志文件。
使用指南
1.添加讀寫權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.在Application的onCreate中初始化
初始化:
LogUtils.init();
注:
- 為了不造成混亂僻澎,這里初始化時不提供自定義配置貌踏。如日志默認TAG,保存路徑窟勃,日志方法棧打印數(shù)量等在代碼中寫死祖乳。
- 根據(jù)BuildConfig.DEBUG參數(shù),debug下會打印到控制臺秉氧,release下控制臺輸出關閉眷昆。
3.打印日志
public static void d(Object message)
public static void d(Object message, boolean isPrStack)
public static void d(String tag, Object message, boolean isPrStack) {
public static void d(String tag,final String message, boolean isPrStack, final Object... args)
public static void json(String json, boolean isPrStack)
public static void log(int priority, String tag, Object message, boolean isPrStack, @Nullable Throwable throwable, Object...args)
注:
- message為打印內(nèi)容,可接收任意參數(shù)。
- isPrStack控制是否打印堆棧信息隙赁。
- 支持對日志字符串格式化垦藏,args為參數(shù)。內(nèi)部會調(diào)用String.format(String format伞访, Object args)掂骏。
- JSON輸出的縮進默認為2,可自行修改厚掷。
- 打印異常信息可調(diào)用log弟灼,傳入Throwable。
- 堆棧打印的方法數(shù)通過METHOD_CCOUNT控制冒黑,默認為8田绑。可以自行修改(可能要考慮線程安全問題抡爹,不過影響也不大)掩驱。
打印JSON結(jié)果
[I][2017-04-20 +8.0 15:52:40.412][12502, 1*][PhiComm][, , 0][Thread:main---{
"name": "BeJson",
"url": "http:\/\/www.bejson.com",
"page": 88,
"isNonProfit": true,
"address": {
"street": "科技園路.",
"city": "江蘇蘇州",
"country": "中國"
},
"links": [
{
"name": "Google",
"url": "http:\/\/www.google.com"
},
{
"name": "Baidu",
"url": "http:\/\/www.baidu.com"
},
{
"name": "SoSo",
"url": "http:\/\/www.SoSo.com"
}
]
}
字符串,堆棧,Throwable打印結(jié)果
[D][2017-04-20 +8.0 15:52:40.411][12502, 1*][Throw][, , 0][Thread:main---{i=zwm, love=joyce}
VMStack.java/dalvik.system.VMStack/getThreadStackTrace/-2
Thread.java/java.lang.Thread/getStackTrace/580
LogUtils.java/com.example.weimingzeng.myapplication.LogUtils/getThreadStack/206
LogUtils.java/com.example.weimingzeng.myapplication.LogUtils/log/232
MainActivity.java/com.example.weimingzeng.myapplication.MainActivity/onCreate/31
Activity.java/android.app.Activity/performCreate/6323
Instrumentation.java/android.app.Instrumentation/callActivityOnCreate/1108
ActivityThread.java/android.app.ActivityThread/performLaunchActivity/2385:java.lang.Throwable
at com.example.weimingzeng.myapplication.MainActivity.onCreate(MainActivity.java:31)
at android.app.Activity.performCreate(Activity.java:6323)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2385)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2492)
at android.app.ActivityThread.access$900(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1358)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5458)
在程序退出時反初始化:
LogUtils.unLoad();
4.解析Log
Log生成完畢后冬竟,會在指定的路徑下生成相應的日志文件:
shell@R7:/sdcard/marssample/log $ ll
-rw-rw---- root sdcard_r 153600 2016-12-30 17:06 MarsSample.mmap2
-rw-rw---- root sdcard_r 29633 2016-12-30 17:06 MarsSample_20161230.xlog
由于使用緩存欧穴,日志只有在應用退出時才會將日志寫入外部存儲。其中MarsSample.mmap2是緩存文件泵殴,不用關心涮帘,我們需要的是.xlog文件,我們把這個文件pull出來笑诅,使用Mars提供的Python腳本進行解密调缨。
找到Mars源碼log/crypt/decode_mars_log_file.py下的這個文件,用python執(zhí)行吆你,生成log文件:
mars_xlog_sdk python decode_mars_log_file.py ~/Downloads/log/MarsSample_20161230.xlog