Android開發學習之Log的使用


Log(android.util.log)是Android Studio中的日志工具類,熟練使用log會對你以后的Android開發之旅有很大的幫助。
* log類有五個方法,分別是(級別由低到高):根據首字母對應VERBOSE,DEBUG,INFO, WARN,ERROR

1.Log.v():打印一些最為繁瑣、意義不大的日志信息
2.Log.d():打印一些調試信息(logd+tab)
3.Log.i():打印一些比較重要的數據,可幫助你分析用戶行為數據(logi+tab)
4.Log.w():打印一些警告信息,提示程序該處可能存在的風險(logw+tab)
5.Log.e():打印程序中的錯誤信息(loge+tab)
(這五個方法都可以進行重載)

注意:不同的打印方法在使用時都是某個方法帶上(String tag, String msg)參數,tag表示的是打印信息的標簽,msg表示的是需要打印的信息。

 

Android Studio中查看log

        Android Studio為開發者提供了良好的log查看工具,開發者可以通過如下方式打開log視圖:View > Tool Windows > Logcat,或者用默認的快捷鍵 Alt+6 打開/隱藏 Logcat視圖。下面簡單介紹一下該工具的使用。

    1、Logcat中選擇篩選條件  

        如下截圖中,標注了Android Studio中使用Logcat視圖的常用功能,開發者可以根據實際情況選擇過濾條件。

    2、Log信息顏色設置

        查看log的時候,有一個小技巧,為了便於查看不同等級的log,Android Studio對不同等級的log信息設置了不同的顏色。開發者也可以根據自己的愛好,自行設置顏色或者其他屬性,這樣,在查看log的時候,就容易對log等級進行區分,查看的時候就比較有層次感。設置路徑為:File > Settings > Editor > Colors & Fonts > Android Logcat。如下截圖所示:

              

        設置完成后,用如下代碼進行測試

復制代碼
1  private void showLog(){
2         Log.v(TAG,"Hello,I am VERBOSE");
3         Log.d(TAG,"Hello,I am DEBUG");
4         Log.i(TAG,"Hello,I am INFORMATION");
5         Log.w(TAG,"Hello,I am WARNNING");
6         Log.e(TAG,"Hello,I am ERROR");
7     }
復制代碼

        logcat視圖中打印的log信息如下:

             

        雖然開發者可以根據自己的愛好設置log的顏色等屬性,但是筆者還是建議讀者盡量遵守約定俗稱的約定,比如,ERROR級別的log,就往往被設置為紅色。

     3、Logcat中的log信息說明

        如下截圖為筆者打印的某條log,對其中各個字段的進行了說明

        

 

四、寫一份便於使用的Log輔助類

    Log的基本使用技能很容易掌握,但是要能靈活地使用在項目中,仍然有很多技巧需要掌握。

    1、開發者常碰到的場景

    在具體的開發中,開發者往往會遇到如下的情形:

    (1)調試的時候,往往會打印不少的log,用於輔助分析問題,但是要發布給用戶使用的版本時,這些log必須要關閉掉。

    (2)開發者往往會在代碼中設置一個變量,比如 boolean isDebug等,來控制日志的打印/關閉。但是每次發布版本的時候,都需要手動去修改這個值,操作不便,甚至容易忘記。

    (3)發布給用戶使用的user版本,log被關閉了,出現bug需要分析的時候,log信息太少,往往又讓開發者感到“巧婦難為無米之炊”,不利於分析問題。

    (4)拿到log信息后,又往往不容易找到這條信息和哪個功能有關,從哪個類,哪個方法中打印出來的。

    (5)有些log需要在user版本中關閉,但有些log需要一直保留,這兩類log的處理,又需要區別對待。

    ······

    諸如此類的情形,想必開發者們都在不斷地經歷着。

    2、輔助工具類代碼

        有經驗的開發者一般都會寫一個Log的輔助類來盡量規避這些麻煩,筆者在開發中也總結了一套代碼,如下代碼所示:

  View Code

注:這套代碼是根據公司的log使用規范來實現的,筆者當前從事手機系統app的開發,上述的處理辦法也相對偏向系統app方面,但是對於純第三方app開發者而言,也是實用的。

    3、輔助類的使用和說明。

    (1)打印基本log

         根據代碼中的注釋,想必對於這些方法的使用和含義,是很容易理解的。下面簡單演示一下使用的例子

         在需要打印log的地方調用 Logger.d(className,methodName,msg);即可,如下演示了輸出后的log

     

        這里提一個小技巧:對於className的獲取,可以采用如下的方法(這里的TAG,就是傳入的Logger.d(...)中的類名了):

public class HandleDemoActivity extends AppCompatActivity {
    private static final String TAG = HandleDemoActivity.class.getSimpleName();
    ......
}

類名.class.getSimpleName()返回的結果就是"HandleDemoActivity",這樣做最大的好處就是,如果類名有變化,這個值也會隨着改變,如果采用硬編碼寫死這個變量,靈活性會比較差。

    (2)打印函數調用棧printStackTraceInfo

       以下截圖展示了函數的調用棧,對於分析某個方法被調用的軌跡非常有用。第二行printStackTraceInfo()方法是最終捕捉調用棧的地方,可以清晰看到其調用軌跡。

       

    (3)打印異常信息printExceptionInfo(Exception pEx)

       該方法主要用打印捕獲的Exception信息,如下截圖一清晰展示地展示了異常原因,發生的地方,已經調用棧等信息。sdk也自帶了e.printStackTrace()方法,由系統自己打印(截圖二)。但是其打印信息被拆分為多條信息打印,在按某個tag進行搜索時,只能搜索到其中含有該tag的信息,而不能整體顯示,自定義的方法就克服了這一點,便於整體查看。當然,讀者可以根據自己愛好來選擇是否用sdk自帶的函數。

                 

                                                      截圖一:自定義的異常打印

                 

                                                截圖二:sdk自帶的異常打印

    (4)使用Log.isLoggable(tagName, level)

       本小結中第1點第(3)條中有提到,調試版本中的log,在user版本中被關閉,這極大地妨礙了對bug的分析。所以在判斷是否允許打印log的條件isTagLoggable(...)中,添加了一個“或”條件,Log.isLoggable(tag, level),就很好地解決了user版本中不能打印部分log的問題。

        1)基本使用

       加上這條件后,在user版本系統中,只要在命令框中執行如下命令即可:

 adb shell setprop log.tag.tagName level

       命令中的tagName為輔助類中的TAG值,即FunctionName,level是指希望輸出的log等級下限,比如,如果level為D,則除VERBOSE外,其他等級更高log都會輸出;level為E,就只有ERROR等級log會輸出。針對該輔助類的具體命令為:

 adb shell setprop log.tag.FunctionName D

輸入該命令后,凡是以“FunctionName”為tag名,等級在DEBUG及以上的log,就都會輸出了。要想恢復到不可打印的狀態,只要重啟手機即可。

      2)相關源碼

  View Code

     3)源碼解讀

       依據以上源碼及注釋,筆者提取了部分信息:

  • 該方法是一個native方法,通過jni在底層實現。
  • 在沒有設置運行打印的tag的等級的時候,默認等級為INFO,即此時isLoggable(tag,level)中的leve如果為VERBOSE或DEBUG,isLoggable()會返回false,其它等級level則會返回true。
  • 此處可以設置的level等級更多,在前面提到的5個等級之后,還有ASSERT、SUPPRESS,設置為SUPPRESS可以關閉所有log。
  • TAG字符串長度不可太長,超過23個后,后面的會被截斷。
  • 注釋中也提供了修改系統文件的方法,來設置允許打印的log的等級。

     4)測試代碼

       如下為一個測試函數

復制代碼
 1 private void testIsLoggable() {
 2         boolean b1 = Log.isLoggable(TAG, Log.VERBOSE);
 3         boolean b2 = Log.isLoggable(TAG, Log.DEBUG);
 4         boolean b3 = Log.isLoggable(TAG, Log.INFO);
 5         boolean b4 = Log.isLoggable(TAG, Log.WARN);
 6         boolean b5 = Log.isLoggable(TAG, Log.ERROR);
 7         Log.e(TAG, "" + b1 + ";" + b2 + ";" + b3 + ";" + b4 + ";" + b5);
 8         Log.v(TAG,"VERBOSE log can be print");
 9         Log.d(TAG,"DEBUG log can be print");
10         Log.i(TAG,"INFO log can be print");
11         Log.w(TAG,"WARN log can be print");
12         Log.e(TAG,"ERROR log can be print");
13     }
復制代碼

     5)測試結果

        a)不執行任何命令,測試結果為:

      

       證明了tag默認level為INFO的結論,但是Log.v() - Log.e() 均能打印出log。

         b)執行命令

adb shell setprop log.tag.HandleDemoActivity I

        測試結果為:

         

          不知道讀者有沒有發現,盡管默認level為INFO,此處命令設置的值也為INFO,但此時Log.v()和Log.d()的msg都沒有再輸出了。

         c) 執行命令

adb shell setprop log.tag.HandleDemoActivity W

       測試結果為:

       

          d)結論

       這里咱們也可以看到,Log.isLoggable(TAG,Log.DEBUG)的值默認是false。咱們在第二節講Log的使用規范時的第2點中提到過,一般信息的打印用DEBUG級別log,再結合前面給出的Log輔助類,在這里可以感受到一些好處了,當然讀者也可以根據自己的理解,利用這些條件設計自己得心應手的使用方法來。

       以上的測試結果,我們還可以得到一個結論:adb shell setprop log.tag.tagName level 不僅會改變Log.isLoggable(tag,level)的返回值,也會影響到Log.v() - Log.e() 是否打印。讀者一定要注意這些細微的差別,筆者剛開始的時候,也忽視過,也曾蒙圈過-_-!

       6)推薦閱讀

         https://blog.csdn.net/qqxiaoqiang1573/article/details/72867776

 

五、log的獲取

      設計好了log的輸入策略,就可以獲取log了。筆者接觸到的獲取log的方式主要有如下幾種 

    1、開發工具中獲取。

       比如上文中提到的Android Studio自帶的Logcat視圖,同樣eclipse中也有該視圖,都比較好用。這種方法主要被開發者使用,測試人員一般不會使用IDE中的類似工具。

    2、adb自帶工具 logcat

       該命令功能也比較強大,使用起來非常方便,不需要額外的IDE,電腦上配置好adb,連接上手機,在命令框中輸入命令即可。該工具的命令也不少,功能也比較強大,可惜,筆者對這個功能用得不多,主要使用IDE自帶工具和手機的Mobile Log。

       推薦閱讀:https://blog.csdn.net/liao277218962/article/details/50129009

    3、手機自帶抓log功能

      一般手機也都自帶了抓取log的工具,不同的品牌和機型,抓取系統log的方式和log的形式也不盡相同,下面以某比亞的某款機型為例來說明。

      (1)在撥號盤中輸入暗碼(可以在網上搜,不同品牌暗碼各不同,同一手機中抓取log的種類也多樣)就會進入到log工具界面,如下所示:

                     

              可以看到,可以抓取的log種類非常多,咱們這里只打開MobileLog。開發者可以根據實際情況選擇開啟需要的log,筆者目前為止,只用到過MoboleLog,-_-

      (2)在使用之前,先點擊“清空”按鈕清理掉之前的log文件, 以免無關log太多,影響查看有用信息。

      (3)點擊“開始”按鈕,系統就開始抓取log了。

      (4)開始操作手機,復現bug等,這段期間產生的log會被捕獲到。

      (5)操作完成后,點擊“關閉”按鈕,系統會生成日志文件,在最底部可以看到日志的存儲路徑,在該路徑下獲取即可。

                     

 

六、查看及分析log

     拿到日志文件后,就可以分析log了。在IDE的視圖工具Logcat中,和adb logcat中獲取的log,基本的查看基本上都會,這里不多說了。這里主要講講MobileLog中log分析。

 1、文檔結構

      進入到log文件夾后,會看到如下的文件夾列表

     

      如果開啟了MobileLog,重啟手機或暫停后重新開啟,均會產生一個最新的日志文件夾。開發者從bug復現最近的一次log開始分析。選擇某個時間段日志文件夾后點擊,會看到如下界面

     

     一般咱們只關注moblie文件夾的內容(筆者目前為止也只使用過該目錄下的文件)。點擊進入后,會顯示log文件列表,如下所示:

   

  2、分析log文件

    (1)log文件概要

     文件名中包含了機型、版本信息,以及文件中log的類型。一般咱們也只需要關注crash、main文件,有時候也會關注system日志文件,其使用情況如下。

  • crash文件中收集了系統中crash的log,首先分析這個文件,看是否有和自己項目相關的crash信息。
  • main文件,咱們前文中講到的添加的log,允許打印的,都會被收集到該文件中。
  • system文件,收集系統的log,系統框架中自帶的log會體現在該文件中,偶爾有需要使用。
  • 其他文件使用得不多,筆者暫時還沒有碰到要使用剩余這幾個文件的場景。

    (2)分析crash文件log

       在crash文件中,可以清晰地看到crash發生的時間,引起crash的進程及包名等信息。這里要注意crash的時間,如果和自己復現的場景時間差得比較遠(比如10分鍾以上),就可能和自己要分析的問題沒太大的關聯度。

     

    (3)分析main文件log

        在main文件中,往往包含了大量的log信息。前面講到的logcat視圖或adb logcat捕獲的log,以及不同機型手機中不同類型的log,其實基本結構基本相同。單條信息中也都包含了日期、時間、進程號、線程號、log等級、TAG,msg等信息。如下圖所示:

        

      在分析這些log的時候,筆者這里提幾個經常用的小技巧:

  • 選一個好用的文本編輯器。筆者和周圍的同事基本上用的都是Notepad++,對查找信息非常有幫助,對於該工具的使用技巧,讀者可以自己網上搜索一下。
  • 結合自己添加log的時候的設計,可以快速根據功能模塊、類名、方法名等關鍵信息,篩選出關聯度高的信息來。
  • 每一個app一般對應一個進程號,如果進程號中途變化了,說明中途該app發生了crash,可以在進程號變化點附近查找bug原因。
  • 最重要一點,對這類的log,就是要大量看。有時候看一遍可能找不出問題,就要反復看,找各種關鍵字搜索,必要時,甚至要逐行逐行看。就像要提升寫作技能,首先必須大量去寫一樣,這是不二法門。

  筆者對MobileLog的分析技巧也在學習和摸索中,此處慢慢積累經驗,慢慢總結,慢慢更新吧。

  3、源碼解析

      在源碼中有如下的代碼

  View Code

       源碼中也正好給出了LOG_ID_MAIN ~ LOG_ID_CRASH 5個LOG_ID值,除了event log外,其它的也是一一對應。Log.v()~Log.e()方法的實現都調用了println_native()方法,傳入其中的第一個參數bufID值也都是LOG_ID_MAIN,正好這些方法輸出的log都保存在了main文件中。筆者尚未找到明確的資料來證明這其中的聯系,但筆者認為,應該不是巧合,讀者有興趣可以自己再深入研究研究。另外,我們也可以發現,println_native()也是個native方法,通過jni在本地實現。

 

七、第三方工具

     當前在app開發生,也出現了不少比較優秀的管理log的第三方工具,筆者使用過的有兩款:log4j和騰訊的bugly,都比較好用。

       個人建議:使用第三方工具,就必然要導入第三方的jar包,sdk等,無疑會增加app的負載。一般來說,如果自己寫的log輔助類能夠輕松實現想要的需求,能不用還是別用吧。當然,個人經驗來看,bugly這類功能不太容易自己實現 -_-


————————————————


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM