android日志分析与记录.

来源:互联网 发布:河北三金网络好不好 编辑:程序博客网 时间:2024/05/02 02:05

同事分享的android日志分析与记录


1. LOG的实现架构

LOG的运行环境

   下图是Android官方网站上给出的Android的Debug环境。




   Android的LOG机制当然也在这个环境中运行。我们重点关注Emulator和Device上运行的部分,App VMs产生LOG信息,并与ADB Device Daemon交互输出这些信息,而ADB Device Daemon又通过相应的协议通过USB(Device)或本地连接(Emulator),与PC上运行的ADB Host Daemon交互,通过PC上的调试工具呈现给用户。JDWP Debugger、DDMS、ADB Host Daemon以及ADB Device Daemon之间的交互与其使用的协议,不在本文讨论范围之内。本文讨论的内容运行在Emulator/Device上,产生LOG信息,并通过程序LogCat输出。

LOG的实现架构

   Android中LOG的实现架构如下图所示,这基本上也是Android的某个模块实现各个层次的经典架构。

 

 

   Android应用程序通过Framework提供的机制操作;Java领域需要本地c/c++提供服务的地方,通过JNI实现;JNI调用底层库;库函数通过操作映射的设备文件操作设备,LINUXkernel中的Driver完成相应的操作。另外,抛开Java和JNI,LINUX上用户域的c/c++程序,也可以通过操作设备文件来完成。 

 

android.util.Log的各种Log记录方法的实现都依赖于native的实现println_native(),Log.v()/Log.d()/Log.i()/Log.w()/Log.e()最终都是调用了println_native()。如Log.d()的实现:

   public static int d(String tag, String msg) {

       return println_native(LOG_ID_MAIN, DEBUG, tag, msg);

   }

 

Native方法println_native()是通过JNI在c/c++中实现的,最终调用内核驱动程序Logger把Log写到内核空间中

 

2,LogCat的过滤

发当中经常看到别人的 log 如洪水般瞬间刷满了屏幕,对自己有用的信息都被淹没了,影响心情也影响效率。下面是几个过滤方法。

1. 只显示需要的输出,白名单

最方便的当然是通过管道使用 grep 过滤了,这样可以使用 grep 强大的正则表达式匹配。简单的匹配一行当中的某个字符串,例如 MyApp:

adb logcat | grep MyApp

adb logcat | grep -i myapp #忽略大小写。

adb logcat | grep --color=auto -i myapp #设置匹配字符串颜色。更多设置请查看 grep 帮助。

进阶一点可以使用 grep 的正则表达式匹配。例如上一个例子会匹配一行中任意位置的 MyApp,可以设置为仅匹配 tag。默认的 log 输出如下,如果修改过输出格式相应的表达式也要修改。

I/CacheService(  665): PreparingDiskCache for all thumbnails.

可以看出 tag 是一行开头的第三个字符开始,根据这点写出表达式:

adb logcat | grep "^..MyApp"

根据这个格式也可以设置只显示某个优先级的 log,再匹配行首第一个字符即可。例如仅显示 Error 级别 tag 为 MyApp 的输出:

adb logcat | grep "^E.MyApp"

当然也可以匹配多个,使用 | 分割多个匹配表达式,要加转义符。例如要匹配 tag 为 MyApp 和 MyActivity 的输出:

adb logcat | grep "^..MyApp\|^..MyActivity"

adb logcat | grep -E "^..MyApp|^..MyActivity"  #使用 egrep 无须转义符

2. 过滤不需要的输出,黑名单

还是使用 grep,用法也跟上面的一样,加一个 -v 即可。例如要过滤 tag 为 MyApp 和 MyActivity 的输出:

adb logcat | grep -v "^..MyApp\|^..MyActivity"

adb logcat | grep -vE "^..MyApp|^..MyActivity"  #使用 egrep 无须转义符

3. 显示同一个进程的所有输出

有时一个程序里面的 tag 有多个,需要输出该程序(同一个 PID)的所有 tag;仅使用 tag 过滤有时也会漏掉一些错误信息,而一般错误信息也是和程序同一个 PID。还是通过 grep 实现,思路是先根据包名找到 pid 号,然后匹配 pid。写成 shell 脚本如下,参数是程序的 java 包名(如 com.android.media)。

查看源代码打印帮助

1

#!/bin/bash

2

packageName=$1

 

3

pid=`adb shell ps | grep $packageName | awk '{print $2}'`

4

adb logcat | grep --color=auto $pid

4. 从当前开始显示

logcat 有缓存,如果仅需要查看当前开始的 log,需要清空之前的。

adb logcat -c && adb logcat

5. 过滤 log 文件

有时需要分析 log 文件,过滤 log 文件还是使用 grep。例如 log 文件为 myapp.log,要匹配 tag 为 MyApp 和 MyActivity 的输出,然后输出到 newmyapp.log:

cat myapp.log | grep "^..MyApp\|^..MyActivity" > newmyapp.log

 

 

3,如何编码实现将同一进程的log文件记录下来

       需要在Application中启动一个线程,在整个程序运行过程中利用logcat来获取log流,并保存在文件中。其中用到了第2部分所介绍的利用Grep和logcat本身的过滤功能来过滤log,获取相应进程的log流。

   private ProcesslogcatProc;

   private BufferedReadermReader =null;

   private boolean mRunning = true;

   String cmds = null;

   private StringmPID;

   private FileOutputStreamout =null

public void run() {

     try {

cmds = "logcat *:v | grep \"(" + mPID +")\"";

logcatProc = Runtime.getRuntime().exec(cmds);

        mReader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()), 1024);

        String line = null;

        while (mRunning && (line =mReader.readLine()) !=null) {

          if (!mRunning) {break; }

          if (line.length() == 0) {

             continue;

          }

          if (out !=null && line.contains(mPID)) {

             out.write((MyDate.getDateEN() +" " + line +"\n").getBytes());

          }

        } 

     } catch (IOException e) {

        e.printStackTrace();

     } finally {

        if (logcatProc !=null) {

          logcatProc.destroy();

          logcatProc = null;

        }

        if (mReader !=null) {

          try {

             mReader.close();

             mReader = null;

          } catch (IOException e) {

             e.printStackTrace();

          }

        }

        if (out !=null) {

          try {

             out.close();

          } catch (IOException e) {

             e.printStackTrace();

          }

          out = null;

        } 

     }  

原创粉丝点击