Flutter异常监控 - 壹 | 从Zone说起
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
如果你正需要处理Flutter异常捕获,那么恭喜你,找对地了,这里从根源上给你准备了Flutter异常捕获需要是所有知识和原理,让你更深刻认识Flutter Zone概念。
Zone是什么
/// A zone represents an environment that remains stable across asynchronous
/// calls.
SDK中描述:表示一个环境,这个环境为了保持稳定异步调用。
通俗理解39 | 线上出现问题,该如何做好异常捕获与信息采集?中描述:
我们可以给代码执行对象指定一个 Zone,在 Dart 中,Zone 表示一个代码执行的环境范围,其概念类似沙盒,不同沙盒之间是互相隔离的。如果我们想要观察沙盒中代码执行出现的异常,沙盒提供了 onError 回调函数,拦截那些在代码执行对象中的未捕获异常。
Zone创建
Dart提供了runZoned方法,支持Zone的快速创建
R runZoned<R>(R body(),
{Map<Object?, Object?>? zoneValues,
ZoneSpecification? zoneSpecification,
@Deprecated("Use runZonedGuarded instead") Function? onError}) {
zoneValues: Zone 的私有数据,可以通过实例zone[key]获取,可以理解为每个“沙箱”的私有数据。zoneSpecification:Zone的一些配置,可以自定义一些代码行为,比如拦截日志输出和错误等
Zone的作用
捕获异常
import 'dart:async';
//OUTPUT:Uncaught error: Would normally kill the program
void main() {
runZonedGuarded(() {
Timer.run(() {
throw 'Would normally kill the program';
});
}, (error, stackTrace) {
print('Uncaught error: $error');
});
}
用try catch一样可以捕获,为啥要通过Zone来捕获?
- Zone回调收拢了异步捕获入口,提高了可维护性。
- 未预料的未捕获异常可以帮你自动捕获到,提高便捷性。
是不是所有异常都可以捕获到?
不是, 只能处理情况1。
Zone默认捕获范围主要针对异步异常或者一般逻辑异常等常规异常,比如Future中出了问题,或者逻辑处理了1/0,(见Tag3),捕获异步异常原理见简话-Flutter异常处理 - 掘金
Dart中另外比较容易出现的异常是framework异常,比如build异常等,这种异常Zone无法捕获到,原因可以参看Flutter异常捕获和Crash崩溃日志收集 。如果想Zone来处理可这样抛给它(见Tag1)
Flutter Engine和Native异常,isolate异常 不是runZonedGuarded和FlutterError.onError 能处理范围。
isolate异常处理(见Tag2)
并发 Isolate 的异常是无法通过 try-catch 来捕获的。并发 Isolate 与主 Isolate 通信是采用 SendPort 的消息机制,而异常本质上也可以视作一种消息传递机制。所以,如果主 Isolate 想要捕获并发 Isolate 中的异常消息,可以给并发 Isolate 传入 SendPort。而创建 Isolate 的函数 spawn 中就恰好有一个类型为 SendPort 的 onError 参数,因此并发 Isolate 可以通过往这个参数里发送消息,实现异常通知。
完整Dart异常捕获代码
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
Zone.current.handleUncaughtError(details.exception, details.stack);//Tag1
//或customerReport(details);
};
//Tag2
Isolate.current.addErrorListener(
RawReceivePort((dynamic pair) async {
final isolateError = pair as List<dynamic>;
customerReport(details);
}).sendPort,
);
runZoned(
() => runApp(MyApp()),
zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
report(line)
},
),
onError: (Object obj, StackTrace stack) {
//Tag3
customerReport(e, stack);
}
);
}
在部分或全部代码中覆盖一组有限的方法
例如print()和scheduleMicrotask()
main() {
runZoned(() {
print("test");
}, zoneSpecification: ZoneSpecification(
print: (self, parent, zone, s) {
parent.print(zone, "hook it: $s");
}
));
}
//OUTPUT:hook it: test
上面实现的原理是什么呢?
简单讲就是runZoned从root Zone fork了一个子Zone,print打印时如果当前Zone
不为空则使用当前Zone的print来打印,而不使用root Zone的print方法。详细见Dart中Future、Zone、Timer的源码学习
每次代码进入或退出区域时执行一个操作
例如启动或停止计时器,或保存堆栈跟踪。
如下例子,Zone提供了一个hook点,在执行其中方法时候,可以做额外包装操作(Tag1,Tag2),比如耗时方法打印,这样在不破坏原有代码基础上实现了无侵入的统一逻辑注入。
import 'dart:async';
final total = new Stopwatch();
final user = new Stopwatch();
final specification = ZoneSpecification(run: <R>(self, parent, zone, f) {
//Tag1
user.start();
try {
return parent.run(zone, f);
} finally {
//Tag2
user.stop();
}
});
void main() {
runZoned(() {
total.start();
a();
b();
c().then((_) {
print(total.elapsedMilliseconds);
print(user.elapsedMilliseconds);
});
}, zoneSpecification: specification);
}
void a() {
print('a');
}
void b() {
print('b');
}
Future<void> c() {
return Future.delayed(Duration(seconds: 5), () => print('c'));
}
输出:
a
b
c
5005
6
将数据(称为 Zone本地值)与各个其他Zone相关联
这个作用类似java中的threadlocal,每个Zone相当于有自己值的作用范围,Zone直接值的传递和共享通过zonevalue来实现。
import 'dart:async';
void main() {
Zone firstZone = Zone.current.fork(zoneValues: {"name": "bob"});
Zone secondZone = firstZone.fork(zoneValues: {"extra_values": 12345});
secondZone.run(() {
print(secondZone["name"]); // bob
print(secondZone["extra_values"]); // 12345
});
}
案例说明:
和Linux类似地,当Zone做Fork的时候,会将父Zone所持有的ZoneSpecification、ZoneValues会继承下来,可以直接使用。并且是支持追加的,secondZone在firstZone的基础之上,又追加了
extra_values属性,不会因为secondZone的ZoneValues就导致name属性被替换掉。
参考链接
Brian Ford - Zones - NG-Conf 2014 - YouTube
2.8 Flutter异常捕获 | 《Flutter实战·第二版》
欢迎搜索公众号:【码里特别有禅】 里面整理收集了最详细的Flutter进阶与优化指南。关注我,获取我的最新文章~
Flutter异常监控 - 壹 | 从Zone说起的更多相关文章
- 【原】聊聊js代码异常监控
在平时的工作,js报错是比较常见的一个情景,尤其是有一些错误可能我们在本地测试的时候测试不出来,当发布到线上之后才可以发现,如果抢救及时,那还好,假如很晚才发 现,那就可能造成很大的损失了.如果我们前 ...
- Sencha Touch 2.2 Store Proxy 异常监控
移动端到服务端通信往往会发生很多莫名的异常情况,如何有效的监控proxy异常,给用户友好的用户体验呢? Proxy给我提供了异常exception的监听事件,只需要监控该项目即可. Sencha To ...
- 从无到有<前端异常监控系统>落地
导火索 有一天一个测试同事的一个移动端页面白屏了,看样子是页面哪里报错了. 我自己打开页面并没有报错,最后发现报错只存在于他的手机,移动端项目又是在微信环境下,调试起来会比较麻烦,最后用他手机调试才 ...
- 业务线接入前端异常监控sentry
1.前端异常处理的框架对比 是否开源 收费 语言 监控范围 sentry 是 自己搭建服务器(免费)价格 英文 Angular.AngularJs.Backbone.Ember.JavaScrip ...
- Fundebug后端Java异常监控插件更新至0.2.0,支持Spring及Maven
摘要: 0.2.0支持监控Spring应用,并且支持使用Maven接入插件,请大家及时更新. 支持监控Spring应用 1. pom.xml配置fundebug-spring依赖 <depend ...
- 异常: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configurat
异常: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. ...
- 前端异常监控 - BadJS
前端异常监控 - BadJS 简介:BadJS 是 web 前端异常监控解决方案,提供一种 web 页面的脚本错误监控.上报.统计.查看等系统化的跟踪解决方案.目前BadJS覆盖了腾讯课堂.公众号.邮 ...
- Asp.net Core全局异常监控和记录日志
前言 系统异常监控可以说是重中之重,系统不可能一直运行良好,开发和运维也不可能24小时盯着系统,系统抛异常后我们应当在第一时间收到异常信息.在Asp.net Core里我使用拦截器 ...
- Fundebug前端异常监控插件更新至2.0.0,全面支持TypeScript
摘要: 是时候支持TS了! Fundebug前端异常监控服务 Fundebug提供专业的前端异常监控服务,我们的插件可以提供全方位的异常监控,可以帮助开发者第一时间定位各种前端异常,包括但不限于Jav ...
- Fundebug前端异常监控插件更新至 1.9.0,支持监控 HTTP 慢请求
摘要: 1.9.0新增 httpTimeout 配置选项,支持监控 HTTP 慢请求,同时修复了记录的 HTTP 响应时间偏小的 BUG. Fundebug提供专业的前端异常监控服务,可以第一时间捕获 ...
随机推荐
- 220722 T4 求和 /P4587 [FJOI2016]神秘数 (主席树)
好久没打主席树了,都忘了怎么用了...... 假设我们选了一些数能构成[0,x]范围内的所有值,下一个要加的数是k(k<=x+1),那么可以取到[0,x+k]内的所有取值,所以有一种做法: 对于 ...
- Java中的多线程的创建方式
首先理清几个基本概念: 程序:为完成特定任务,用某种语言编写的一组指令的集合.即一段静态的代码(还没运行起来) 进程:是程序的一次执行过程,也就是说程序运行起来了,加载到了内存中,并占用了cpu的资源 ...
- 动态编译库 Natasha 5.0 兼容版本发布
Natasha 5.0 版本已于 2022/10/10 日发布, 此次大版本更迭带来了兼容性支持, 目前 Natasha 可以兼容 standard2.0 及 coreapp3.1 以上版本. 下载使 ...
- Java递归查找层级文件夹下特定内容的文件
递归查找文件 引言 或许是文件太多,想找某个文件又忘记放哪了;又或者是项目改造,需要将外部调用接口进行改造,项目太多,又无法排查.那么怎么快速找到自己想要的内容就是一件值得思考的事情了. 根据特定内容 ...
- ARC144 D - AND OR Equation
ARC144 D - AND OR Equation Solution 首先可以猜测和答案仅和每一个二进制位以及\(f(0)\)有关系,不妨把按位\(\operatorname{AND}\)和按位\( ...
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
文章目录 1.工厂方法创建对象 1.1 代码块 1.2.测试结果 2.原型对象 2.1 代码 2.2 测试结果 3.toString 3.1 代码 3.2 测试结果 4.数组 4.1 代码 5.字面量 ...
- 教你用canvas打造一个炫酷的碎片切图效果
前言 今天分享一个炫酷的碎片式切图效果,这个其实在自己的之前的博客上有实现过,本人觉得这个效果还是挺炫酷的,这次还是用我们的canvas来实现,代码量不多,但有些地方还是需要花点时间去理解的,需要点数 ...
- raid 5搭建部署
raid 5搭建部署 软raid与备份 1.用四块磁盘做实验,三块盘搭建raid阵列组,有一块当作备份可以使用raid 5来搭建三块磁盘的阵列组 创建命令如下: [root@xiaohaoge ~]# ...
- 5 why 分析法,一种用于归纳抽象出解决方案的好方法
最近在看了<微信背后的产品观 - 张小龙手抄版>,其中有段话如下: 用户需求是零散的,解决方案是归纳抽象的过程 那如何归纳抽象呢?是否有一定的实践方法论呢?经过一轮探讨和学习,有这些答案: ...