适用于 iOS 和 Android 原生应用的 Elastic® APM 在 v8.12 版本中正式发布。Elastic iOS 和 Android APM 代理是开源的,并且是在 OpenTelemetry Swift 和 Android SDK/API 之上开发的,即作为它们的发行版。
移动 APM 解决方案概述
适用于 iOS 和 Android 的 OpenTelemetry SDK/API 支持 HTTP 请求的自动检测、手动检测的 API、基于 OpenTelemetry 语义约定的数据模型以及缓冲支持等功能。此外,Elastic APM 代理发行版还支持更简单的初始化过程和新颖的功能,如远程配置和基于用户会话的采样。Elastic iOS 和 Android APM 代理作为发行版,按照 Elastic 的标准支持条款和条件进行维护。
Kibana® 中提供了精选或预构建的仪表板,用于监控、数据分析和故障排除。下面显示的服务概览视图提供了相关的前端 KPI,如崩溃率、HTTP 请求、平均应用加载时间等,包括比较视图。
此外,用户流量的地理分布可在地图上按国家和地区级别查看。服务概览仪表板还显示了吞吐量、延迟、失败事务率以及按设备制造商型号、网络连接类型和应用版本划分的流量分布等指标的趋势。
下面显示的事务视图突出显示了不同事务组的性能,包括具有关联跨度、错误和崩溃链接的单个事务的分布式跟踪端到端。此外,用户可以一目了然地看到按设备制造商和型号、应用版本和操作系统版本划分的流量分布。
如下面突出显示的位于事务选项卡底部的表格视图,可以相对轻松地查看设备制造商和型号、应用版本等如何影响延迟和崩溃率。
下面显示的错误和崩溃视图可用于分析不同的错误和崩溃组。在此视图中还提供单个错误或崩溃实例的未符号化 (iOS) 或混淆 (Android) 堆栈跟踪。
下面显示的服务地图视图提供了端到端服务相互依赖关系的可视化,包括任何第三方 API、代理服务器和数据库。
Kibana 中用于观察移动前端的综合预构建仪表板提供了对错误、崩溃和瓶颈来源的可见性,从而简化了生产环境中问题的故障排除。底层的 Elasticsearch® 平台还支持查询原始数据、构建自定义指标和自定义仪表板、警报、SLO 和异常检测的功能。总而言之,该平台提供了一套全面的工具来加快根本原因分析和修复,从而促进高速度的创新。
一些错误场景的调试工作流程演练
接下来,我们将提供 iOS 和 Android 原生应用中几个错误场景的配置详细信息和故障排除工作流程演练。
场景 1
在此示例中,我们将使用 Apple 的崩溃报告符号化以及面包屑来调试异步方法中的崩溃,以推断崩溃的原因。
符号化
在此场景中,用户注意到“错误和崩溃”选项卡中特定崩溃组的崩溃发生率激增,并决定进一步调查。在“崩溃”选项卡中出现新的崩溃,开发人员按照以下步骤在本地对崩溃报告进行符号化。
- 通过 UI 复制崩溃并将其粘贴到具有以下名称格式的文件中:<应用二进制名称>_<日期时间>。例如,“opbeans-swift_2024-01-18-114211.ips`”。
- Apple 提供了有关如何通过 Xcode 自动或使用命令行手动在本地对该文件进行符号化的详细说明。
面包屑
第一个线程的第二帧显示崩溃发生在 Worker 实例中。
此实例实际上在很多地方使用,并且由于此函数的异步性质,无法立即确定此调用来自何处。尽管如此,我们可以利用 Open Telemetry SDK 的功能向这些崩溃添加更多上下文,然后将这些信息拼凑起来以找到崩溃的位置。
通过在此 Worker 实例周围添加“面包屑”,可以跟踪哪些对 Worker 的调用实际与此崩溃相关联。
示例
在 Worker 类中创建一个记录器提供程序作为公共变量,以便于访问,如下所示
在调用 Worker.doWork() 函数的每个位置创建面包屑
每个面包屑都将使用相同的事件名称“worker_breadcrumb”,以便可以一致地查询它们,并且将使用“来源”属性进行区分。
在此示例中,Worker.doWork() 函数是从 CustomerRow 结构(一个在“onTapGesture”上执行工作的表行)调用的。如果您要从 CustomerRow 结构中的多个位置调用此方法,您还可以向“来源”属性值添加其他区分,例如关联的函数(例如,“CustomerRow#onTapGesture”)。
现在,该应用正在报告这些面包屑,我们可以使用 Discover 来查询它们,如下所示
_注意:_ 代理发送的事件_名称_在 Elastic Common Schema (ECS) 中转换为事件_操作_,因此请确保查询使用此字段。
-
您可以添加一个过滤器
event.action:“worker_breadcrumb”它显示了从这个新的面包屑生成的所有事件。 -
您还可以看到各种来源:ProductRow、CustomerRow、CartRow 等。
-
如果您向查询中添加 error.type : crash,您可以看到崩溃以及面包屑
时间线中彼此相邻的崩溃和面包屑可能来自完全不同的设备,因此我们需要另一个区分符。对于每个崩溃,我们都有一个元数据,其中包含与崩溃关联的 session.id,可以从“元数据”选项卡中查看。我们可以使用此 session.id 进行查询,以确保我们在 Discover 中查看的唯一数据来自导致崩溃的单个用户会话(即,单个设备)。
在 Discover 中,我们现在可以通过面包屑查看单个设备上有关崩溃的会话事件流,如下所示
看起来崩溃之前的最后一个面包屑来自“CustomerRow”面包屑。现在,这为应用开发人员提供了一个很好的起点来开始他们的根本原因分析或调查。
场景 2
_注意:_ 此场景需要 Elastic Android 代理版本“0.14.0”或更高版本。
一个 Android 示例应用有一个由两个片段组成的表单(
问题
我们开始在 Kibana 的“错误和崩溃”选项卡中看到崩溃发生率激增(空指针异常),这些崩溃似乎总是发生在表单的最后一个屏幕上,当用户单击“完成”按钮时。尽管如此,这并非总是可重现的,因此仅通过查看崩溃的堆栈跟踪无法明确根本原因。这是它看起来的样子
当我们查看堆栈跟踪中引用的代码时,这就是我们所看到的
这是发生崩溃的代码行,看起来是因为在执行这段代码时,变量“formId”(这是一个位于“FirstPage”中的静态字符串)为空,导致引发了空指针异常。这个变量是在后端请求完成以检索 ID 后,在“FirstPage”片段中设置的。到达“SecondPage”的唯一方法是经过“FirstPage”。因此,仅仅通过堆栈跟踪无法获得太多帮助,因为页面必须按顺序打开,并且第一个页面始终会设置“formId”变量。因此,“SecondPage”中的 formId 为空的可能性似乎不大。
查找根本原因
除了查看崩溃的堆栈跟踪之外,查看补充数据也可能很有用,这些数据可以帮助我们将碎片拼凑在一起,更全面地了解当我们的应用发生崩溃时还发生了哪些其他事情。在本例中,我们知道表单 ID 必须来自我们的后端服务,因此我们可以首先排除后端调用出现错误的可能性。我们通过查看事务详细信息视图中创建 FirstPage 片段的跟踪记录来做到这一点,其中执行了表单 ID 请求。
“已创建”跨度表示创建第一个片段所花费的时间。最上面的跨度显示了 Activity 的创建,然后是 NavHostFragment,然后是“FirstScreen”。创建后不久,我们看到向后端发出了一个 GET HTTP 请求以检索我们的表单 ID,并且根据跟踪记录,GET 请求已成功。因此,我们可以排除此问题的后端通信存在问题。
另一种选择是查看在应用发生崩溃的会话期间发送的日志(我们也可以查看来自我们应用的所有日志,但它们太多了,无法分析这一个问题)。为此,我们首先复制 span 详细信息弹出窗口中可用的一个 span 的 “session.id” 值(任何 span 都可以,因为在崩溃发生期间从我们的应用发送的所有数据中都可以使用相同的会话 ID)。
_ 注意: _ 相同的会话 ID 也可以在崩溃元数据中找到。
现在我们已经确定了我们的会话,我们可以打开日志浏览器视图,查看同一会话中我们应用的所有日志,如下所示
通过查看日志并添加一些字段来显示应用的生命周期状态和错误类型,我们可以看到从我们的应用自动收集的日志事件。我们可以看到列表顶部的崩溃事件,它是最新的一个。我们还可以看到我们应用的生命周期事件,如果我们继续滚动,我们将看到一些有助于找到根本原因的生命周期事件
我们可以看到有几个生命周期事件告诉我们,应用在会话期间重新启动过。这是一个重要的提示,因为它意味着 Android 操作系统在某个时候杀死了我们的应用,这在应用在后台停留一段时间时很常见。有了这些信息,我们可以尝试通过强制操作系统在后台杀死我们的应用来重现该问题,然后看看从最近打开的应用菜单中重新打开时它的行为如何。
尝试之后,我们能够重现该问题,并且发现当应用重新启动时,静态的“formId”变量丢失了,导致当 SecondPage 片段请求它时为空。我们现在可以研究将参数传递给片段的最佳实践,以便我们可以更改我们的代码,防止依赖静态字段,而是在屏幕之间存储和共享值,从而防止再次发生此崩溃。
额外说明: 对于这种情况,我们依靠 APM Agent 自动发送的事件就足够了;但是,如果这些事件对于其他情况不够,我们可以始终通过 OpenTelemetry 事件 API 在我们想要跟踪应用状态更改的位置发送自定义事件,如下面的代码片段所示
充分利用您的 Elastic APM 体验
在这篇文章中,我们回顾了 Elastic 在 8.12 版本中推出的全新 Mobile APM 解决方案。这个新解决方案使用 Elastic 的全新 iOS 和 Android APM 代理,这些代理是开源的,并且是在 OpenTelemetry Swift 和 Android SDK/API 的基础上开发的,即作为它们的发行版。
我们还回顾了 iOS 和 Android 原生应用中两种错误场景的配置详情和故障排除工作流程。
-
iOS 场景: 使用 Apple 的崩溃报告符号化以及面包屑来调试异步方法中的崩溃,从而推断出崩溃的原因。
-
Android 场景: 分析为什么用户在点击表单的“完成”按钮时会在最后一个屏幕上收到空指针异常。通过查看崩溃的堆栈跟踪,分析这一点并不总是很清楚,而且不容易重现。
在这两种情况下,我们都使用来自移动设备的分布式跟踪以及相关的日志找到了崩溃的根本原因。希望这篇博客回顾了 Elastic 如何帮助管理和监控移动原生应用。
Elastic 邀请 SRE 和开发人员亲身体验我们的 Mobile APM 解决方案,并在他们的数据任务中开启新的视野。立即在 https://ela.st/free-trial 试用。
本文中描述的任何特性或功能的发布和时间安排均由 Elastic 自行决定。任何当前不可用的特性或功能都可能不会按时或根本不会交付。