安卓 App 内 logcat 日志查看
为方便安卓APP在开发、测试阶段的调试,需要在手机端实时查看到logcat打印情况,因此可在APP中加入一个全局悬浮窗效果的日志查看功能,作为测试阶段的调试工具。
1. logcat 介绍 1.1 简介 Android日志系统提供了记录和查看系统调试信息的功能,日志从各种软件和系统的缓冲区中记录下来的,缓冲区可通过logcat命令查看使用。
1.2 开发者选项 要使用logcat需先打开开发者选项,有一个选项叫“日志记录器缓冲区大小”,默认是256K,日志循环写入环形缓冲区,在通常情况下,写满时最旧的日志会被删除以给新输出的日志留出内存空间。
1.3 logcat缓冲区 Android log 输出量巨大,特别是通信系统的log,因此,Android把log输出到不同的缓冲区中,目前定义的有四个log缓冲区:
1 2 3 4 Radio : 输出通信系统的log,如:WiFi,蓝牙,3/4/5G,GPS,NFC等 System: 输出系统组件的log,权限比较高,如:调用相机,调用录制,调用麦克风等 Events: 输出event模块的log,event翻译过来就是事件,如:通过手指点击屏幕的某一处地方,称为点击事件;通过按电源或者音量加减等 Main: 所有java层的log,(不属于上面3层的log)
如果测试APP需要输出Main的日志,命令:adb logcat -b radio,adb logcat 默认抓取Main。
1.4 日志组成部分
写下日志的时间,如上中 “05-22 12:27:15.370”
优先级,在Android 中,日志的优先级从低到高分成以下几种:
1 2 3 4 5 V ---Verbose(啰嗦,最低级别,开发调试中的一些详细信息,仅在开发中使用,不可在发布产品上打开) D ---Debug(调试,用于调试的信息,可以在发布产品中关闭,比较常见) I ---Info(信息,一般提示性的消息) W ---Warning(警告) E ---Error(错误,已经出现可影响运行的错误,比如应用crash时输出的日志)
标签(tag),标明日志发起者和方便日志的过滤筛选,如上中“libTGL”
PID(进程ID),如上中 “1438”
正文,本日志的主体内容
2. logcat 命令 logcat有许多命令可供使用,在终端输入不同命令可对logcat实现不同操作。
2.1 实时输出指定标签内容 1 2 logcat -s TAG 仅输出标签为TAG的日志我们想输出 "CameraHal" 标签的信息, 就可以使用logcat -s CameraHal;
2.2 输出日志信息到文件 1 2 3 4 5 6 7 logcat -f /data/log.txt 日志保存到log.txt中 logcat -r 1 -n 4 -f /data/log.txt 将日志文件保存到log.txt中,当日志文件大于1K字节时,日志保存在log.txt1中,直到下标到达n-1时,重新覆盖log.txt中的信息,循环覆盖 -r 每<kbytes> 时 输出日志,默认值为16,需要和-f 选 项一起使用 -n 设置日志的最大数目<count> ., 默认值是4,需要和 -r 选 项一起使用
2.3 过滤固定字符串 1 2 3 4 5 logcat | grep -i <str> 显示包含,并忽略大小写的logcat logcat | grep <str> 显示包含的logcat
2.4 清空日志缓存信息 1 2 logcat -c 将之前的日志信息清空, 重新开始输出日志信息
2.5 过滤格式输出 1 2 3 4 5 6 7 8 9 10 11 标签:日志等级 V : Verbose (明细) D : Debug (调试) I : Info (信息) W : Warn (警告) E : Error (错误) F : Fatal (严重错误) S : Silent(Super all output) (最高的优先级, 可能不会记载东西) logcat *:E 显示 Error 以上级别的日志
2.6 将缓存日志输出 1 2 logcat -d 输出命令, 之后推出命令, 不会进行阻塞
2.7 指定 logcat 的日志输出格式 日志消息包含一个元数据字段,除了标签和优先级,还可以修改输出显示一个特定的元数据字段格式的消息。为此,使用logcat -v 选项来指定一个支持的输出格式。支持的格式有:
格式
说明
brief
显示优先级/标记和过程的PID发出的消息(默认格式)
process
只显示PID
tag
只显示优先级/标记
raw
显示原始的日志消息,没有其他元数据字段
time
调用显示日期、时间、优先级/标签和过程的PID发出消息
threadtime
调用显示日期、时间、优先级、标签遗迹PID TID线程发出的消息
long
显示所有元数据字段与空白行和单独的消息
1 2 3 adb logcat –v thread 只能指定一个输出格式-v
3.应用内日志打印 3.1 获取日志 设置打印格式:logcat -v tag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 /** * 打印log,子线程 */ private suspend fun printLogCat() { printLog = true withContext(Dispatchers.IO) { try { //1.获取日志数据 val cmdLog = "logcat -v tag" val process = Runtime.getRuntime().exec(cmdLog) val bufferedReader = BufferedReader(InputStreamReader(process.inputStream)) var line: String? while (printLog) { if (bufferedReader.readLine().also { line = it } != null) { line?.let { if (it.contains(logcatGrep)) { withContext(Dispatchers.Main) { //2.处理日志数据 buildLogLine(it) } } } } } } catch (e: IOException) { e.printStackTrace() } } }
3.2 处理日志数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 /** * 处理日志数据给log分等级添加颜色、时间戳 * 存到list中,在recycleview中显示 */ private fun buildLogLine(line: String?) { line?.let { var color = getColor(com.york.common.R.color.green) if (it.startsWith("D")) { color = getColor(com.york.common.R.color.blue_light) } else if (it.startsWith("W")) { //如果是上一条警告,本条忽略。只打印第一条 if (logList.size > 1 && logList[logList.lastIndex].content.startsWith("W")) { return } color = getColor(com.york.common.R.color.yellow) } else if (it.startsWith("E")) { color = getColor(com.york.common.R.color.red_notification) } val logLine = LogLine(System.currentTimeMillis(), line, color) //限制一下,100行 if (logList.size > 100) { logList.removeAt(0) } logList.add(logLine) logcatAdapter.setList(logList) //自动滚动到底部 if (scrollToBottom) { floatingLogcatBinding?.rcvLogcat?.scrollToPosition(logList.size - 1) } } }