前言

最近阅读 Catcher、BugSnag、Rollbar 三个 Flutter 异常监控开源框架,文章链接如下:

Flutter 异常监控 - 壹 | 从 Zone 说起

Flutter 异常监控 - 贰 | 框架 Catcher 原理分析

Flutter 异常监控 - 叁 | 从 bugsnag 源码学习如何追溯异常产生路径

Flutter 异常监控 - 肆 | Rollbar 源码赏析

这篇文章将从实现功能,优缺点,设计思想等方面做个总结,方便开发中技术选型。

需求列表

罗列下认为比较重点需求,并不表示框架所有需求只有这些。

功能对比

所有上述需求主要体现在异常产生到发送过程中,大致包括如下几个方面

CatcherBugsnagRollbar
自定义 UI 显示异常是(4 种报告模式)不支持不支持
异常处理线程main isolate对端决定子 isolate
自定义包装过程部分支持不支持支持
异常存储不支持对端存储Dart 侧存储
自定义上报处理程序6 种1 种(自研)1 种(自研)
异常路径生成追溯不支持自动 + 手动手动
是否纯 Dart 实现Dart对端+DartDart
对端异常处理不支持支持部分支持
是否有自研后台
支持平台全平台android,iosandroid,ios

框架的好与坏

如果问哪个最牛逼,我只能说:“没有不好的框架,只有乱用的人”。谁又不是个(某人心中的)宝宝呢?不同场景下谁都是自己的王者。

正确食用方式:

应用场景
Catcher如果对异常 UI 显示和自定义上报要求很高,且支持全平台,可以选 Catcher。
Bugsnag如果对端各平台 SDK 有深耕和技术积累,可以参考 Bugsnag 来统一 Dart 端接口设计和自动埋点。
Rollbar如果侧重功能可插拔,对 UI 性能要求高,重度 Dart 用户且未来需要支持全平台,可以选 Rollbar。

论变与不变

设计模式中最重要的原则是开闭原则,23 种设计模式都是以开闭原则为核心。

开闭原则:“对扩展开放,对修改关闭。” ,其中关键是识别需求中的变与不变,封装变化隔离不变。

用 Rollbar 框架举例:

拿复用代码来说,变化的是多平台及多平台中不同的网络和存储实现,不变的是各平台都需要实现这套异常网络上报和存储逻辑。隔离不变,就是将网络和存储放在 Dart 侧,封装变化,将不同平台捕获异常方式封装起来放到各自对应平台目录实现,这样就达到了复用代码目的。

这块可以看下Flutter 异常监控 - 肆 | Rollbar 源码赏析 中的代码复用分析,这里就不赘述了。

拿线程控制来说,变化的是在哪个线程,不变的是在线程中做的事情。Rollbar 中抽象 Notifier 来对线程控制,隔离不变,从 Config 中获取 Wrangler,Sender,Telemetry 来对异常事件进行操作,先存储再包装最后发送,这些是异常处理的标准流程,封装变化,将线程切换封装在 Notifier 中。

Flutter 异常谁来上报

这三个开源项目,总结下来分两个流派:

  1. 自力派纯 Dart 实现,啥都是自己干,比如 Catcher 和 Rollbar
  2. 借力派,Flutter 侧负责搜集 Flutter 异常,收集好解析好,给对端 SDK 负责上报,典型代表有 bugsnag 和 Sentry。

有人会说,管它白猫黑猫抓到老鼠就是好猫,只要能上报后台看到结果不就 OK 了,管那么多干嘛,领导又不在乎这个。回答 Flutter 异常谁上报的实质是回答下面三个问题:

Flutter 与宿主的关系

你认为 Flutter 是掌控全局(ios android ,window,web…)的大佬还是跟随其他平台的小弟?

从创建一个新的 Flutter 项目伊始 Flutter 官方就给出了答案,flutter create 命令结束,可看到 ios 和 android。。。 目录,这些目录理解成差异目录,表示同一个功能对应不同平台的实现是什么,然后将实现填充在其中。

没错 Flutter 是掌控全局的人,他定义了一套统一的 Dart 侧接口供各平台差异实现,各差异目录作用是为处理差异化功能而非因宿主已有现成功能方便桥接用。

显然,按 Flutter 是大佬的思路,站在多平台统一的上帝视角来看,Flutter 异常范围是包括其他平台异常的,比如其他平台的 OOM 等而非单纯考虑 Dart 侧异常。

代码复用问题

用一个场景来说明问题:如果按照不同平台维度建立项目,相同项目则对应不同平台,如果按照 Flutter 来建立项目就是一个。

那么问题来了,是在安卓端和 ios 端分别建立一套数据存储异常呢,还是将不同平台异常收拢到 Flutter 平台来统一管理和上报?

显然考虑到代码复用和人力成本,大可将其他平台异常抛都给 Flutter 侧来处理和上报,存储和上报都可复用,后台也一套代码。

迁移成本

很多开源库喜欢将 flutter 作为小弟角色,异常都给到对端,这样导致的问题也很明显,安卓和 ios 两个后台异常系统都会出现 flutter 异常数据,默认存储两份上报两次,比如 Bugsnag,这时肯定有人会说 Bugsnag 垃圾,强依赖对端,通用性不行,复用性不行。

但我们需要看到更深层次原因:迁移成本。

软件开发本来就是一个迭代过程,是先有安卓和 ios 再有 Flutter ,人家已经在各自平台有稳定的 crash-sdk 了,推翻不用重新弄一套的行为太过激进,势必存在原来上报系统的重构和迁移,稳定性先不论,平白就增加了很多开发和测试的人力成本,不划算,直接桥接到原来功能岂不更好。

如图,人家就是每个平台都已经有 SDK 了,而且 star 上 bugsnag-android 比 bugsnag-flutter 多得多,这叫先来后到,稳。

Untitled.png
Untitled 1.png

一种异常框架设计思路

依赖反转是不错的思路,子平台将异常收集传递给 Flutter 统一管理和上报。管理和上报本来就是各端通用能力,没必要浪费人力各端重复实现,异常的情况每个平台接口都不一样,这种差异化的 api 就应该由各个平台来实现,刚好契合 Flutter 中目录分治理念。

有点像代码设计的思路,如果是通用的代码需要提取处理作为公共使用,如果有差异部分就应该分到各个子类中取实现。lib 中负责是各个平台公共部分,存在差异的是各个平台捕获异常的 api 方式。

读源码在读什么

看需求,当前整个框架实现了哪些功能,跟自己想到的需求实现方式上有什么不同。

其次就是看不足,看不足可以对框架理解更深。如 Catcher 的局限性是它不支持异常的本地序列化断网了就发送不了,而且没自己后台,仅仅侧重于 Adapter 角色;Bugsnag 又太依赖对端,支持异常序列化断网仍可发送,但不是 Flutter 本身实现而是对端能力,Bugsnag 的扩展性相对于 Catcher 来说就差很多,包括多平台的适配上来说比不上 Catcher,但它有自己后台有盈利能力。

最后是看设计,如 Rollbar 中对类设计模块抽象精准且优美,单一原则和开闭原则做得很好。Catcher 中对 UI 显示和处理程序的开闭也做得很好,有时候看大佬们的设计思想只会觉得”编程即艺术”。

如果觉得文章对你有帮助,点赞、收藏、关注、评论,一键四连支持,你的支持就是我创作最大的动力。
❤️ 欢迎关注公众号:编程黑板报  原创技术文章第一时间推送! ❤️

唯你
62 声望3 粉丝