Logcat
使用 Logcat 写入和查看日志 | Android 开发者 | Android Developers https://developer.android.google.cn/studio/debug/am-logcat?hl=zh-cn
使用 Logcat 写入和查看日志
Android Studio 中的 Logcat 窗口会显示系统消息,例如在进行垃圾回收时显示的消息,以及使用 Log
类添加到应用的消息。Logcat 可以实时显示消息,也可以保留历史记录,因此您可以查看较早的消息。
要仅显示感兴趣的信息,您可以创建过滤器、修改消息中显示的信息量、设置优先级、仅显示通过应用代码生成的消息以及搜索日志。默认情况下,Logcat 仅显示与最近运行的应用相关的日志输出。
如果应用抛出异常,Logcat 会显示一条消息,后跟相关联的堆栈轨迹,其中包含指向相应代码行的链接。
运行窗口会显示当前运行的应用的日志消息。您可以配置 Logcat 输出显示,但无法配置运行窗口。
查看应用日志
如需显示应用的日志消息,请执行以下操作:
- 在设备上构建和运行应用。
- 依次点击 View > Tool Windows > Logcat,或点击工具窗口栏中的 Logcat 图标
。
Logcat 窗口会显示从窗口顶部菜单中选择的应用的日志消息,如图 1 所示。
默认情况下,Logcat 仅显示在设备上运行的应用的日志消息。若要更改此默认设置,请参阅如何过滤 Logcat 消息。
Logcat 工具栏中提供以下按钮:
- Clear Logcat
:点击此按钮可以清除显示的日志。
- Scroll to the end
:点击此按钮可以跳转到日志底部并查看最新的日志消息。如果您先点击此按钮,然后点击日志中的某一行,则视图会在相应位置暂停滚动。
- Up the stack trace
和 Down the stack trace
: 点击相应按钮可以在日志的堆栈轨迹中进行上下导航,从而选择输出的异常中显示的上一个或下一个文件名。这与您在日志中点击某个文件名时的行为相同。
- Use soft wraps
:点击此按钮可以启用换行并防止水平滚动。不过,所有非间断字符串仍然需要进行水平滚动。
- Print
:点击此按钮可以输出 Logcat 消息。在显示的对话框中选择输出偏好设置后,您还可以选择将消息保存为 PDF 格式。
- Restart
:点击此按钮可以清除日志并重启 Logcat。与 Clear Logcat 按钮不同,此按钮可以恢复并显示之前的日志消息,因此当 Logcat 无响应而您又不想失去日志消息时,此按钮是最有用的。
- Logcat header
:点击此按钮可以打开 Configure Logcat Header 对话框,在该对话框中,您可以自定义各个 Logcat 消息的外观,例如是否显示日期和时间。
- Screen capture
:点击此按钮可以截取屏幕截图。
- Screen record
:点击此按钮可以录制设备屏幕的视频(时长不超过 3 分钟)。
写入日志消息
通过 Log
类,您可以创建日志消息,这些消息会显示在 Logcat 中。每个 Android 日志消息都有一个与之相关联的标记和优先级。系统日志消息的标记是一个简短的字符串,指示消息所源自的系统组件。
应使用以下日志方法,这些方法按照优先级从高到低的顺序列示:
- 错误:
Log.e(String, String)
- 警告:
Log.w(String, String)
- 信息:
Log.i(String, String)
- 调试:
Log.d(String, String)
- 详细程度:
Log.v(String, String)
用户定义的标记可以是您认为有用的任何字符串,例如当前类的名称。您可以在 Log
方法调用中定义标记,例如:
有关更完整的选项列表,请参阅 Log
类说明。
除开发期间外,其他任何时候都绝不应将详细日志记录编译到您的应用中。调试日志会被编译,但在运行时会被删除。错误、警告和信息日志会始终保留。
对于每种日志方法,第一个参数都应是唯一标记,第二个参数都应是消息。系统日志消息的标记是一个简短的字符串,指示消息所源自的系统组件。标记可以是您认为有用的任何字符串,例如当前类的名称。
一种比较好的做法是,在要用于第一个参数的类中声明 TAG
常量。例如,您可以按如下方式创建一条信息日志消息:
private const val TAG = "MyActivity"
...
Log.i(TAG, "MyClass.getView() — get item number $position")
注意:长度超过 23 个字符的标记名称在 Logcat 输出中会被截断。
Logcat 消息格式
日志消息的格式为:
date time PID-TID/package priority/tag: message
PID 代表“进程标识符”,TID 则为“线程标识符”。如果仅有一个线程,两者可以相同。
例如,下面的日志消息的优先级为 V
,标记为 AuthZen
:
12-10 13:02:50.071 1901-4229/com.google.android.gms V/AuthZen: Handling delegate intent.
设置日志级别
您可以通过设置日志级别来控制 Logcat 中显示所有消息,还是仅显示指示最严重情况的消息。
无论日志级别设置如何,Logcat 都会继续收集所有消息。此设置仅决定 Logcat 显示什么。
在 Log level 菜单中,选择以下值之一:
- Verbose:显示所有日志消息(默认值)。
- Debug:显示仅在开发期间有用的调试日志消息,以及此列表中较低的消息级别。
- Info:显示常规使用情况的预期日志消息,以及此列表中较低的消息级别。
- Warn:显示尚不是错误的潜在问题,以及此列表中较低的消息级别。
- Error:显示已经引发错误的问题,以及此列表中较低的消息级别。
- Assert:显示开发者预计绝不会发生的问题。
搜索 Logcat 消息
若要搜索 Logcat 中当前显示的消息,请执行以下操作:
- (可选)如果您想要使用正则表达式搜索模式,请选择 Regex。
- 在搜索字段
中输入字符序列。
Logcat 输出会相应地显示更改。
- 按 Enter 键以在此会话期间将搜索字符串保存到菜单中。
- 若要重复搜索,请从搜索菜单中选择。根据需要选择或取消选择 Regex。
过滤 Logcat 消息
将日志输出减少至可管理水平的一种方法是,使用过滤器施加限制。
注意:过滤器会应用于 Logcat 的全部历史记录,而不仅仅是 Logcat 中当前显示的消息。确保适当地设置其他显示选项,以便您能够看到想要检查的过滤器输出。
若要定义并应用过滤器,请执行以下操作:
- 在过滤器菜单中,选择一个过滤选项:
- Show only selected application:仅显示通过应用代码生成的消息(默认选项)。Logcat 使用正在运行的应用的 PID 来过滤日志消息。
- No Filters:不应用过滤器。无论您选择哪个进程,Logcat 都会显示设备中的所有日志消息。
- Edit Filter Configuration:创建或修改自定义过滤器。例如,您可以创建一个过滤器,以同时查看两个应用中的日志消息。
定义过滤器后,您还可以在菜单中选择它们。若要从菜单中移除过滤器,删除它们即可。
- 如果您选择了 Edit Filter Configuration,请创建或修改过滤器:
- 在“Create New Logcat Filter”对话框中指定过滤器参数:
- Filter Name:输入要设定的过滤器的名称,或者从左侧窗格中选择现有过滤器以便修改。名称只能包含小写字符、下划线和数字。
- Log Tag:(可选)指定标记。
- Log Message:(可选)指定日志消息文本。
- Package Name:(可选)指定软件包名称。
- PID:(可选)指定进程 ID。
- Log Level:(可选)选择日志级别。
- Regex:选择此选项可以为相应参数使用正则表达式语法。
- 点击 +,将过滤器定义添加到左侧窗格中。
若要移除过滤器,请在左侧窗格中将其选中,然后点击 -。
- 完成后,点击 OK。
- 在“Create New Logcat Filter”对话框中指定过滤器参数:
如果您没有看到所需的日志消息,请选择 No filters 并搜索特定日志消息。
读取垃圾回收消息
有时,发生垃圾回收 (GC) 事件时,相应消息会输出到 Logcat 中。
如需详细了解应用的内存,请使用内存分析器。
Dalvik 日志消息
在 Dalvik(而不是 ART)中,每个 GC 都会将以下信息输出到 Logcat 中:
D/dalvikvm(PID): GC_Reason Amount_freed, Heap_stats, External_memory_stats, Pause_time
例如:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
在日志消息积聚时,请注意堆统计数据的增大情况。如果此值继续增大,可能会出现内存泄漏。
Dalvik 日志消息中包含以下字词:
- GC 原因
- 什么触发了 GC 以及是哪种回收。可能的原因包括:
GC_CONCURRENT
- 在您的堆开始占用内存时释放内存的并发 GC。
GC_FOR_MALLOC
- 您的堆已满而系统不得不停止您的应用并回收内存时,您的应用尝试分配内存而引起的 GC。
GC_HPROF_DUMP_HEAP
- 当您请求创建 HPROF 文件来分析堆时发生的 GC。
GC_EXPLICIT
- 显式 GC,例如当您调用
gc()
时。不过,请避免调用此方法,而应信任 GC 会根据需要运行。 GC_EXTERNAL_ALLOC
- 外部分配内存的 GC,例如存储在原生内存或 NIO 字节缓冲区中的像素数据。 这仅适用于 API 级别 10 及更低级别。更新的版本会在 Dalvik 堆中分配任何内存。
- 释放量
- 从此次 GC 中回收的内存量。
- 堆统计数据
- 堆的可用空间百分比与(活动对象数量)/(堆总大小)。
- 外部内存统计数据
- API 级别 10 及更低级别的外部分配内存(已分配内存量)/(发生回收的限值)。
- 暂停时间
- 堆越大,暂停时间越长。并发暂停时间显示两个暂停:一个出现在回收开始时,另一个出现在回收快要完成时。
ART 日志消息
与 Dalvik 不同,ART 不会为未明确请求的 GC 记录消息。仅在 GC 为显式或 GC 暂停时间超过 5 毫秒或 GC 持续时间超过 100 毫秒时,系统才会输出 GC 消息。如果应用未处于可察觉到暂停的状态(例如应用在后台运行时,这种情况下,用户无法察觉 GC 暂停),则除了显示 GC 外的任何 GC 信息都不会被输出。
ART 会在其垃圾回收日志消息中包含以下信息:
I/art: GC_Reason GC_Name Objects_freed(Size_freed) AllocSpace Objects, Large_objects_freed(Large_object_size_freed) Heap_stats LOS objects, Pause_time(s)
例如:
I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms
ART 日志消息中包含以下字词:
- GC 原因
- 什么触发了 GC 以及是哪种回收。可能的原因包括:
Concurrent
- 不会挂起应用线程的并发 GC。此 GC 在后台线程中运行,而且不会阻止分配。
Alloc
- 由于应用在堆已满时尝试分配内存而引发的 GC。在这种情况下,垃圾回收在分配线程中发生。
Explicit
- 由应用明确请求的垃圾回收,例如,通过调用
System.gc()
或Runtime.gc()
。 不过,与 Dalvik 一样,在 ART 中,最佳实践是您信任 GC 并避免请求显式 GC(如果可能)。不建议请求显式 GC,因为它们会阻止分配线程并不必要地浪费 CPU 周期。此外,如果显式 GC 导致其他线程被抢占,则也可能会导致卡顿(应用出现卡顿、抖动或暂停)。 NativeAlloc
- 原生分配(例如位图或
RenderScript
分配对象)导致出现原生内存压力,进而引起的 GC。 CollectorTransition
- 由堆转换引起的 GC。这由在运行时变更 GC 策略引起,例如应用在可察觉到暂停的状态之间切换时。回收器转换包括将所有对象从空闲列表空间复制到碰撞指针空间(反之亦然)。
回收器转换仅在以下情况下出现:在搭载低于 Android 8.0 版本的低 RAM 设备上,应用将进程状态从可察觉到暂停的状态(例如应用在前台运行时,这种情况下,用户可以察觉 GC 暂停)更改为察觉不到暂停的状态(反之亦然)。
HomogeneousSpaceCompact
- 同构空间压缩是空闲列表空间到空闲列表空间压缩,通常在应用进入到察觉不到暂停的进程状态时发生。这样做的主要原因是减少内存使用量并对堆进行碎片整理。
DisableMovingGc
- 这不是 GC 原因,但请注意,由于在发生并发堆压缩时使用了
GetPrimitiveArrayCritical
,因此回收遭到阻止。一般情况下,强烈建议不要使用GetPrimitiveArrayCritical
,因为它在移动回收器方面存在限制。 HeapTrim
- 这不是 GC 原因,但请注意,在堆修剪完成之前,回收会一直受到阻止。
- GC 名称
- ART 具有可以运行的多种不同的 GC:
Concurrent mark sweep (CMS)
- 整个堆回收器,会回收除映像空间以外的所有其他空间。
Concurrent partial mark sweep
- 几乎整个堆回收器,会回收除映像空间和 Zygote 空间以外的所有其他空间。
Concurrent sticky mark sweep
- 分代回收器,只能释放自上次 GC 后分配的对象。此垃圾回收比完整或部分标记清除运行得更频繁,因为它更快速且暂停时间更短。
Marksweep + semispace
- 非并发、复制 GC,用于堆转换以及同构空间压缩(对堆进行碎片整理)。
- 释放的对象
- 此 GC 从非大型对象空间回收的对象数量。
- 释放的大小
- 此 GC 从非大型对象空间回收的字节数量。
- 释放的大型对象
- 此垃圾回收从大型对象空间回收的对象数量。
- 释放的大型对象大小
- 此垃圾回收从大型对象空间回收的字节数量。
- 堆统计数据
- 可用空间百分比与(活动对象数量)/(堆总大小)。
- 暂停时间
- 通常情况下,暂停时间与 GC 运行时修改的对象引用数量成正比。当前,ART CMS GC 仅在 GC 即将完成时暂停一次。移动 GC 的暂停时间较长,会在 GC 的大部分时间持续。
如果您在 Logcat 中看到大量 GC 消息,请注意堆统计数据的增大情况。如果此值继续增大,且始终没有变小的趋势,可能会出现内存泄漏。
或者,如果您看到原因为“Alloc”的 GC,则您已快要达到堆容量上限,并且很快会出现内存不足异常。
最后更新时间 (UTC):2022-12-22。
Logcat 命令行工具 | Android 开发者 | Android Developers https://developer.android.google.cn/studio/command-line/logcat?hl=zh-cn#java
Logcat 命令行工具
Logcat 是一个命令行工具,用于转储系统消息日志,包括从您的应用使用 Log
类写入的消息。
本页介绍了命令行 logcat
工具,但在 Android Studio 中,您也可以从 Logcat 窗口查看日志消息。如需了解如何在 Android Studio 中查看和过滤日志,请参阅使用 Logcat 写入和查看日志。
日志记录系统概览
Android 日志记录系统是系统进程 logd
维护的一组结构化环形缓冲区。这组可用的缓冲区是固定的,并由系统定义。最相关的缓冲区为:
main
:存储大多数应用日志。system
:存储源自 Android OS 的消息。crash
:存储崩溃日志。每个日志条目都包含一个优先级、一个标识日志来源的标记以及实际的日志消息。
日志记录系统的 C/C++ 主接口是共享库 liblog
及其头文件 <android/log.h>
。所有语言特定的日志记录工具(包括 android.util.Log
)最终都会调用函数 __android_log_write
。默认情况下,它会调用函数 __android_log_logd_logger
,该函数使用套接字将日志条目发送到 logd
。从 API 级别 30 开始,可通过调用 __android_set_log_writer
更改日志记录函数。如需了解详情,请参阅 NDK 文档。
运行 adb logcat
显示的日志要经过四个级别的过滤:
- 编译时过滤
- 根据编译设置,某些日志可能会从二进制文件中完全移除。例如,可以将 ProGuard 配置为从 Java 代码中移除对
Log.d
的调用。 - 系统属性过滤
liblog
会查询一组系统属性以确定要发送到logd
的最低严重级别。如果日志具有MyApp
标记,系统会检查以下属性,并且日志应包含最低严重级别的第一个字母(V
、D
、I
、W
、E
或S
以停用所有日志):
log.tag.MyApp
persist.log.tag.MyApp
log.tag
persist.log.tag
- 应用过滤
- 如果未设置任何属性,
liblog
会使用__android_log_set_minimum_priority
设置的最低优先级。默认设置为INFO
。 - 显示过滤
adb logcat
支持其他可减少logd
显示的日志数量的过滤条件。如需了解详情,请参阅有关过滤日志输出的部分。
命令行语法
如需通过 adb
shell 运行 logcat
,一般用法如下:
[adb] shell logcat [<option>] ... [<filter-spec>] ...
此外,还有一种 adb logcat
的简写形式,但它仅会扩展为 adb shell logcat
。
选项
logcat
提供了很多选项。具体有哪些可用选项取决于您使用的设备的操作系统版本。如需查看特定于所用设备的 logcat
帮助,请执行以下命令:
adb logcat --help
请注意,由于 logcat
是面向操作系统开发者和应用开发者的工具(预计应用开发者会使用 Android Studio),因此许多选项只有在取得 root
权限的情况下才可使用。
过滤日志输出
日志消息的标记是一个简短的字符串,指示消息所源自的系统组件。例如,“View”表示视图系统。
优先级是以下字符值之一(按照从最低到最高优先级的顺序排列):
-
V
:详细(最低优先级)D
:调试I
:信息W
:警告E
:错误F
:严重错误S
:静默(最高优先级,绝不会输出任何内容)
如需获取系统中使用的带有优先级的标记列表,请运行 logcat
并观察每条消息的前两列,格式为 <priority>/<tag>
。
以下是使用 logcat -v brief output
命令获取的简短 logcat
输出的示例。此输出表明消息与优先级“I”和标记“ActivityManager”相关:
I/ActivityManager( 585): Starting activity: Intent { action=android.intent.action...}
如要将日志输出降低到可管理的水平,请使用过滤表达式限制日志输出。借助过滤表达式,您可以向系统指明您感兴趣的标记-优先级组合。系统会针对指定的标记抑制其他消息。
过滤表达式采用 tag:priority ...
格式,其中 tag
表示您感兴趣的标记,priority
表示可针对该标记报告的最低优先级。不低于指定优先级的标记的消息会写入日志。在一个过滤表达式中提供任意数量的 tag:priority
规范。一系列规范使用空格分隔。
以下是一个过滤表达式的示例,该表达式会抑制除标记为“ActivityManager”、优先级不低于“信息”的日志消息,以及标记为“MyApp”、优先级不低于“调试”的日志消息以外的所有其他日志消息:
adb logcat ActivityManager:I MyApp:D *:S
上述表达式中最后一个元素 *:S
将所有标记的优先级设为“静默”,从而确保系统仅显示标记为“ActivityManager”和“MyApp”的日志消息。使用 *:S
可确保日志输出受限于您已明确指定的过滤器。*:S
可以让过滤器充当日志输出的“许可名单”。
注意:在某些 shell 中,“*
”字符已被 shell 预留。如果您使用的是此类 shell,请将过滤表达式用引号括起来:adb logcat "ActivityManager:I MyApp:D *:S"
以下过滤器表达式显示了优先级不低于“警告”的所有标记的所有日志消息:
adb logcat *:W
如果您从开发计算机运行 logcat
(而不是在远程 adb
shell 上运行),则也可以通过导出环境变量 ANDROID_LOG_TAGS
的值设置默认过滤表达式:
export ANDROID_LOG_TAGS="ActivityManager:I MyApp:D *:S"
如果您从远程 shell 或使用 adb shell logcat
运行 logcat
,系统不会将 ANDROID_LOG_TAGS
过滤器导出到模拟器/设备实例。
控制日志输出格式
除标记和优先级外,日志消息还包含许多元数据字段。您可以修改消息的输出格式,以便它们显示特定的元数据字段。为此,请使用 -v
选项,并指定下列某一受支持的输出格式:
brief
:显示优先级、标记以及发出消息的进程的 PID。long
:显示所有元数据字段,并使用空白行分隔消息。process
:仅显示 PID。raw
:显示不包含其他元数据字段的原始日志消息。tag
:仅显示优先级和标记。thread:
:旧版格式,显示优先级、PID 以及发出消息的线程的 TID。threadtime
(默认值):显示日期、调用时间、优先级、标记、PID 以及发出消息的线程的 TID。time
:显示日期、调用时间、优先级、标记以及发出消息的进程的 PID。
启动 logcat
时,您可以使用 -v
选项指定所需的输出格式:
[adb] logcat [-v <format>]
以下示例显示了如何生成输出格式为 thread
的消息:
adb logcat -v thread
您只能使用 -v
选项指定一种输出格式。不过,您可以视需要指定任意数量的有意义的修饰符。logcat
会忽略没有意义的修饰符。
格式修饰符
格式修饰符会更改 logcat
输出。如要指定格式修饰符,请使用 -v
选项,如下所示:
adb logcat -b all -v color -d
每个 Android 日志消息都有一个与之相关联的标记和优先级。您可以将任何格式修饰符与以下任一格式选项进行组合:
brief
long
process
raw
tag
thread
threadtime
time
如要获取以下格式修饰符详细信息,请在命令行中输入 logcat -v --help
。
color
:使用不同的颜色来显示每个优先级。descriptive
:显示日志缓冲区事件说明。此修饰符仅影响事件日志缓冲区消息,不会对其他非二进制文件缓冲区产生任何影响。事件说明取自 event-log-tags 数据库。epoch
:显示自 1970 年 1 月 1 日以来的时间(以秒为单位)。monotonic
:显示自上次启动以来的时间(以 CPU 秒为单位)。printable
:确保所有二进制日志记录内容都进行了转义。uid
:如果访问权限控制允许,则显示 UID 或记录的进程的 Android ID。usec
:显示精确到微秒的时间。UTC
:显示世界协调时间 (UTC)。year
:将年份添加到显示的时间。zone
:将本地时区添加到显示的时间。
查看备用日志缓冲区
Android 日志记录系统为日志消息保留了多个环形缓冲区,而且并非所有的日志消息都会发送到默认的环形缓冲区。如要查看其他日志消息,您可以使用 -b
选项运行 logcat
命令,以请求查看备用的环形缓冲区。您可以查看下列任意备用缓冲区:
radio
:查看包含无线装置/电话相关消息的缓冲区。events
:查看已经过解译的二进制系统事件缓冲区消息。main
:查看主日志缓冲区(默认),不包含系统和崩溃日志消息。system
:查看系统日志缓冲区(默认)。crash
:查看崩溃日志缓冲区(默认)。all
:查看所有缓冲区。default
:报告main
、system
和crash
缓冲区。
以下是 -b
选项的用法:
[adb] logcat [-b <buffer>]
以下示例显示了如何查看包含无线装置和电话相关消息的日志缓冲区。
adb logcat -b radio
如需为要输出的所有缓冲区指定多个 -b
标记,请输入以下命令:
logcat -b main -b radio -b events
指定一个 -b
标记,后跟缓冲区的逗号分隔列表,例如:
logcat -b main,radio,events
通过代码记录日志
借助 Log
类,您可以在代码中创建日志条目,而这些条目会显示在 logcat
工具中。常用的日志记录方法包括:
Log.v(String, String)
(详细)Log.d(String, String)
(调试)Log.i(String, String)
(信息)Log.w(String, String)
(警告)Log.e(String, String)
(错误)
例如,使用以下调用:
logcat
输出与以下内容类似:
I/MyActivity( 1557): MyClass.getView() — get item number 1
最后更新时间 (UTC):2023-03-21。