使用Log的一些姿勢

NO IMAGE

20161113147902764731467.jpg

LOG 是任何一種程式語言的第一個API,通常被初學者用來列印 Hello, World!。 有研究顯示,
不使用 LOG 或者使用姿勢錯誤的人,感情路都走得很辛苦,有七成的比例會在 34 歲的時候跟自己不愛的人結婚,而其餘三成的人最後只能把遺產留給自己的貓。畢竟愛情需要書寫,不能是一整張白紙。

LogCat是Android開發者們最熟悉不過的日誌列印工具,幾乎每一個Android專案裡面都包含著大量的Log相關程式碼。不過,或許是因為Log實在是太過於普通,所以許多人在使用它的時候就顯得非常隨意,這些錯誤的使用姿勢卻會在不經意間給我們帶來不少的大坑。

Log相關的一些問題

沒有關閉除錯用的LOG

許多同學喜歡在開發階段用Log輸出當前的一些環境資料,用於除錯程式碼,但是在除錯完成後卻忘了關閉這些Log,導致發版出去的應用裡面還會繼續輸出這些LOG,這樣不僅會造成不必要的效能丟失,也會暴露一些敏感的資料,這些都是我們不願看到的。

首先,我們要給Log進行分級,規定“DEBUG版本輸出哪一些級別的LOG並遮蔽哪一些級別的LOG,而RELEASE版本又輸出另一些級別的LOG並遮蔽另一些級別的LOG”,這樣在開發階段能夠輸出我們除錯需要的LOG,而同時又能保證放送的版本能夠遮蔽這些敏感的LOG。但是在開發階段我們不應該特意去注意這些細節,所以必須開發一個Log工具庫,在框架層級解決這個需求。

同時,需要注意的是,用於作為“開啟/關閉Log”的開關必須是一個常量,而不能是一個變數(使用常量的話,在編譯程式碼的時候,如果常量為false),編譯器會直接把除錯部分的Log程式碼直接去掉,而使用變數作為開關的話,這個判斷邏輯會繼續保留,一方面會造成效能丟失,另一方面在執行時也可以通過Hack手段強行開啟這部分Log程式碼。

另外,“開啟/關閉Log”的開關必須寫在Log方法外部,也就是說必須先判斷“開啟/關閉Log”條件,再呼叫Log方法,因為在呼叫Log方法的時候已經造成了效能丟失,而且呼叫方法的時候,會先構造好改方法需要的引數(按照引數順序從右往左),再呼叫方法,而許多人喜歡在呼叫Log方法的時候計算需要列印出來的內容,這裡是最容易造成效能丟失的地方。因此,如果為了圖方便,寫一個Log工具類,在工具類內部去判斷是否應該開啟或關閉Log,事實上已經造成了不少的效能丟失。正確的使用姿勢應該是:

public static final boolean DEBUG = true;
if (DEBUG) {
Log.v(TAG, "log something");
}

在迴圈體內部列印LOG

儘管Log造成的效能損失很小,但是如果在迴圈體內部迴圈呼叫Log方法的話,那總體的丟失的非常可觀了,所以不應該在迴圈體內部使用Log,正確的做法是在迴圈體內部拼接需要列印的內容,等跳出迴圈體再一次列印出來。

除了常見的迴圈體外,還要一個需要注意的場景就是Adapter。ListView/RecyclerView是Android開發中最常用的控制元件,因此Adapter使用的情景也很多。滾動螢幕的時候,ListView/RecyclerView會在通過Adapter頻繁地繫結ItemView和資料,而且這些都是在UI執行緒裡進行的,所以如果在繫結的過程中呼叫Log,可能會造成明顯的卡頓。

至於Log到底會丟失多少效能,一般情況下,Log的效能丟失很小,畢竟是這麼常見的系統Api,肯定是身經百戰,早就是“best performance”了。不過我曾經有個RecyclerView在MIUI上非常卡,一開始我是RecyclerView佈局沒優化好,最終定位到Adapter內部的一處Log上,卡頓的地方出現在Log的Native實現。MIUI到底對使用者輸出的日誌做了什麼處理呢?非常神奇。

無法獲取重要LOG內容

在除錯程式碼的時候,我們經常通過LOG來定位Bug。同理,當線上的版本出現問題的時候,我們也希望能通過LOG來定位問題所在。但是問題是使用者的裝置上的列印出來的LOG我們根本沒有方法獲取,唯一的手段就是當使用者裝置出現問題的時候,把裝置借過來連上IDE用LogCat檢視輸出的LOG……顯然這是不可行的。

這種時候,我們可以在列印重要LOG(比如重要路徑的觸發點、或者一些異常類的資訊)的時候,一併把這些資訊記錄到檔案裡。在使用者反饋系統裡面,一併將這些檔案上傳到我們的使用者反饋伺服器,這樣在處理反饋問題的時候,就能拿到重要的參考日誌了。

BLog

BLog 是 Android SDK 的 LOG 工具 {@Link android.util.Log} 的加強版,以方便在開發時用來
操作除錯日誌。

特點

  1. 簡單易用的API;

  2. 支援輸出執行緒資訊;

  3. 支援設定LogLevel,方便在生產環境關閉除錯用的LOG;

  4. 支援將LOG內容寫入檔案,以便通過檔案LOG定位使用者反饋的問題;

注意,儘管BLog支援關閉Log的輸出,但是在你呼叫 BLog.v(String) 的時候,其實已經造成了效能
丟失,所以請儘量使用正確的姿勢來使用BLog,比如

if (BuildConfig.DEBUG) {
BLog.v(TAG, "log verbose");
}

Getting Started

GitHub : https://github.com/kaedea/b-log
出處 : 使用 Log 的正確姿勢