Android-Gradle 运行单元测试时抓取 logcat 日志

需求

就是运行android测试的时候抓取系统日志,遇到的主要问题包括:

  1. adb logcat 指定起始时间( not in time format 错误 );
  2. 如何保存单元测试开始时间;
  3. gradle中执行 adb 命令;

ADB 获取 logcat

用法与问题

使用 adb logcat 命令可以抓取logcat日志 (可参考官方文档)
但是在不加控制选项的情况下,默认是抓取所有时间的日志的,我们只希望抓取单元测试开始到结束时的日志。
针对此需求,我们查阅官方文档可以看到有个 -t 的选项可以指定起始时间:

-t ‘

官方也给出了示例用法如下:

adb logcat -t '01-26 20:52:41.820'

可以看到使用了一个单引号包围,主要是为了保留空格,但是,当我们按照这种写法进行测试的时候,却报错了:

$ adb logcat -t '05-19 11:32:00.000'
logcat: -t ''05-19' not in time format.
  • 我还注意到,官方页面还温馨的给了一个链接( -P 选项),但是其中的描述也是使用单引号。
  • 猜想可能是文档更新不及时?于是通过 adb 自带帮助看看:
$ adb logcat --help
  -t <count>                  Print only the most recent <count> lines (implies -d).
  -t '<time>'                 Print the lines since specified time (implies -d).
  -T <count>                  Print only the most recent <count> lines (does not imply -d).
  -T '<time>'                 Print the lines since specified time (not imply -d).
                              count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
                              'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.

还是一样,😂😂😂😂,这就很让人无语了。

解决

怎么解决的? 灵机一动🤞,换成了双引号,就pass了。不得不说,Google 也挺坑😂。

$ adb logcat -t "2022-05-19 11:41:56.000"
--------- beginning of main
05-19 11:41:56.626  1740  2360 E WifiScoringParams: Invalid frequency(-1), using 5G as default rssi array

保存单元测试时间

执行单元测试时,我们通过 connectedDebugAndroidTest 的gradle任务来进行触发。
很自然的,我们先获取到 该任务,然后在它的 doFirst 方法中保存时间,问题就在于这个时间保存到什么地方?

    tasks.findByName("connectedDebugAndroidTest").doFirst {
        saveTestStartTime()
    }
  1. 最初想到的是存储在 project 的属性中,即: project.properties.put() 但是,在我们使用在另外一个任务中去取时,无法取到;
  2. 当然,可以存储在一个指定文件中,但是还是倾向于存储到内存中,毕竟这个文件没啥用
  3. 又想到使用 extensions,即 project.extensions.add() ,测试后确实可以获取到,故最后的模式如下:
tasks.findByName("connectedDebugAndroidTest").doFirst {
        saveTestStartTime()
}

// 保存开始时间
private void saveTestStartTime() {
    project.extensions.add("testTaskStartTime", new SimpleDateFormat("MM-dd HH:mm:ss.mmm").format(new Date()))
    String startTime = project.extensions.getByName("testTaskStartTime")
    logger.lifecycle("startTime=" + startTime)
}

// 获取开始时间
private String getTestStartTime() {
    try {
        String startTime = project.extensions.getByName("testTaskStartTime")
        startTime = "\"$startTime\""
        logger.lifecycle("startTime=" + startTime)
        return startTime
    } catch (ignored) {
        return null
    }
}

执行 adb 命令

获取adb路径

为了保证能在不同的机器上都能找到adb,所以我们需要动态的获取adb的路径。
很自然的想到通过 local.properties 文件获取:

sdk.dir=D\:\\ProgramFiles\\Android\\Sdk

读取 local.properties 文件,然后取出 sdk.dir 属性即可:

private String getAdbExecPath() {
    String adbPath = getStringProp("sdk.dir", null)
    if (adbPath == null) {
        return null;
    }
    String osName = System.getProperty("os.name")
    String ext = osName.contains("Windows") ? ".exe" : ""
    File adb = new File(adbPath, "${File.separator}platform-tools${File.separator}adb$ext")
    if (!adb.exists()) {
        logger.lifecycle("adb不存在:" + adb.getAbsolutePath())
        return null
    }
    return adb.getAbsolutePath()
}

String getStringProp(String name, String defaultValue) {
    String value = null
    File localProp = project.rootProject.file('local.properties')
    if (localProp.exists()) {
        Properties p = new Properties()
        p.load(new FileInputStream(localProp))
        value = p.get(name)
    }
    if (value == null) {
        value = getProperties().get(name)
    }
    return (value == null) ? defaultValue : value;
}
执行adb命令

就是通过 Runtime.getRuntime().exec() 执行命令即可

// 添加测试完成抓取logcat日志的操作任务
project.afterEvaluate {
    String adbPath = getAdbExecPath()
    tasks.create("getLogcatToFile") {
        group = "custom"
        doLast {
            String startTime = getTestStartTime()
            File logFile = rootProject.file("report/html/${project.name}_${timeStamp()}.log")
            Runtime runtime = Runtime.getRuntime();
            String cmd
            if (startTime == null) {
                cmd = adbPath + " logcat -d";
            } else {
                cmd = adbPath + " logcat -d " + " -t $startTime"
            }
            logger.lifecycle("cmd: $cmd")
            Process process = runtime.exec(cmd)
            outputToFile(logFile, process.getInputStream())
            logger.lifecycle("adb日志抓取完毕")
        }
    }
    tasks.findByName("connectedDebugAndroidTest").finalizedBy("getLogcatToFile")
}
private static String timeStamp() {
    return new SimpleDateFormat("YYYY-MM-dd_HH-mm").format(new Date())
}

完成后执行 connectedDebugAndroidTest 任务即可自动抓取日志到指定的文件中。

延申

运行gradle任务抓取所有logcat

创建一个Gradle Task,去掉adb logcat 命令中的时间戳即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值