来源: 开课吧前端团队

https://mp.weixin.qq.com/s/4UyEHM-YmdgrfF_yze9Bpg

本篇文章读后,你将GET的技能:

●收集前端错误(原生、React、Vue)

●编写错误上报逻辑

●利用Egg.js编写一个错误日志采集服务

●编写webpack插件自动上传sourcemap

●利用sourcemap还原压缩代码源码位置

●利用Jest进行单元测试

有没有心动的感觉?赶紧跟然叔学起来吧!

一、如何捕获异常

JS异常:js异常的特点是,出现不会导致JS引擎崩溃 最多只会终止当前执行的任务。
比如一个页面有两个按钮,如果点击按钮发生异常页面,这个时候页面不会崩溃。
只是这个按钮的功能失效,其他按钮还会有效☟

上面的例子我们用setTimeout分别启动了两个任务。
虽然第一个任务执行了一个错误的方法。程序执行停止了。但是另外一个任务并没有收到影响。
其实如果你不打开控制台都看不到发生了错误。好像是错误是在静默中发生的。
下面我们来看看这样的错误该如何收集。

try-catch:
JS作为一门高级语言我们首先想到的使用try-catch来收集。

如果在函数中错误没有被捕获,错误会上抛。

控制台中打印出的分别是错误信息和错误堆栈。
读到这里大家可能会想那就在最底层做一个错误try-catch不就好了吗。
确实作为一个从java转过来的程序员也是这么想的。
但是理想很丰满,现实很骨感。我们看看下一个例子。

大家注意运行结果,异常并没有被捕获。
这是因为JS的try-catch功能非常有限一遇到异步就不好用了。
那总不能为了收集错误给所有的异步都加一个try-catch吧,太坑爹了。
其实你想想异步任务其实也不是由代码形式上的上层调用的就比如本例中的settimeout。
大家想想eventloop就明白啦,其实这些一步函数都是就好比一群没娘的孩子出了错误找不到家大人。
当然我也想过一些黑魔法来处理这个问题比如代理执行或者用过的异步方法。
算了还是还是再看看吧。

二、异常任务捕获

window.onerror:

window.onerror 最大的好处就是可以同步任务还是异步任务都可捕获。

onerror返回值
onerror还有一个问题大家要注意 如果返回返回true 就不会被上抛了。
不然控制台中还会看到错误日志。

监听error事件:
文件中的位置☟window.addEventListener('error',() => {})
其实onerror固然好但是还是有一类异常无法捕获。这就是网络异常的错误。
比如下面的例子。

<img src="./xxxxx.png">

试想一下我们如果页面上要显示的图片突然不显示了,而我们浑然不知那就是麻烦了。
addEventListener就是☟

运行结果如下☟

Promise异常捕获:
Promise的出现主要是为了让我们解决回调地域问题。基本是我们程序开发的标配了。
虽然我们提倡使用es7 async/await语法来写。但是不排除很多祖传代码还是存在Promise写法。

new Promise((resolve, reject) => {  abcxxx()});

这种情况无论是onerror还是监听错误事件都是无法捕获的。

除非每个Promise都添加一个catch方法。
但显然,我们不能这样做。

window.addEventListener("unhandledrejection", e => { console.log('unhandledrejection',e)});

我们可以考虑将unhandledrejection事件捕获错误抛出交由错误事件统一处理就可以了。

async/await异常捕获:

实际上async/await语法本质还是Promise语法。
区别就是async方法可以被上层的try/catch捕获。

如果不去捕获的话就会和Promise一样,需要用unhandledrejection事件捕获。
这样的话我们只需要在全局增加unhandlerejection就好了。

小结:

实际上我们可以将unhandledrejection事件抛出的异常再次抛出就可以统一通过error事件进行处理了。
最终用代码表示如下:

三、前端工程化

Webpack工程化:

现在是前端工程化的时代,工程化导出的代码一般都是被压缩混淆后的。
比如:

setTimeout(() => {    xxx(1223)}, 1000)

出错的代码指向被压缩后的JS文件,而JS文件长下图这个样子。

如果想将错误和原有的代码关联起来,那就需要sourcemap文件的帮忙了。

sourceMap是什么?
简单说,sourceMap就是一个文件,里面储存着位置信息。
仔细点说,这个文件里保存的,是转换后代码的位置,和对应的转换前的位置。
那么如何利用sourceMap对还原异常代码发生的位置这个问题,我们到异常分析这个章节再讲。

四、VUE、React创建工程

VUE创建工程

利用vue-cli工具直接创建一个项目。

为了测试的需要我们暂时关闭eslint 这里面还是建议大家全程打开eslint。
在vue.config.js进行配置

我们故意在(文件位置☟)
src/components/HelloWorld.vue

这个时候 错误会在控制台中被打印出来,但是错误事件并没有监听到。

handleError:

为了对Vue发生的异常进行统一的上报,需要利用vue提供的handleError句柄。
一旦Vue发生异常都会调用这个方法。
我们在src/main.js

React:

npx create-react-app react-samplecd react-sampleyarn start

我们l用useEffect hooks 制造一个错误:

并且在src/index.js中增加错误事件监听逻辑:

window.addEventListener('error', args => {    console.log('error', error)})

但是从运行结果看虽然输出了错误日志但是还是服务捕获。

五、Error Boundary标签

Error Boundary 标签

错误边界仅可以捕获其子组件的错误。
错误边界无法捕获其自身的错误。
如果一个错误边界无法渲染错误信息,则错误会向上冒泡至最接近的错误边界。
这也类似于 JavaScript 中 catch {} 的工作机制。
创建ErrorBoundary组件

在src/index.js中包裹App标签☟

最终运行的结果:

六、异常上报

动态创建img标签:

其实上报就是要将捕获的异常信息发送到后端。最常用的方式首推动态创建标签方式。
因为这种方式无需加载任何通讯库,而且页面是无需刷新的。
基本上目前包括百度统计 Google统计都是基于这个原理做的埋点。

new Image().src ='http://localhost:7001/monitor/error'+ '?info=xxxxxx'

通过动态创建一个img,浏览器就会向服务器发送get请求。
可以把你需要上报的错误数据放在querystring字符串中,利用这种方式就可以将错误上报到服务器了。

Ajax上报:
实际上我们也可以用ajax的方式上报错误,这和我们再业务程序中并没有什么区别。

上报哪些数据:

上报哪些数据:

我们先看一下error事件参数:

其中核心的应该是错误栈,其实我们定位错误最主要的就是错误栈。
错误堆栈中包含了绝大多数调试有关的信息。其中包括了异常位置(行号,列号),异常信息

上报数据序列化:
由于通讯的时候只能以字符串方式传输,我们需要将对象进行序列化处理。
大概分成以下三步:1、将异常数据从属性中解构出来,存入一个JSON对象2、将JSON对象转换为字符串
3、将字符串转换为Base64

当然在后端也要做对应的反向操作 这个我们后面再说。

七、异常上报后端服务器

异常上报的后端服务器

搭建eggis工程:

异常上报的数据一定是要有一个后端服务接收才可以。
我们就以比较流行的开源框架eggjs为例来演示

# 全局安装egg-clinpm i egg-init -g # 创建后端项目egg-init backend --type=simplecd backendnpm i# 启动项目npm run dev

编写error上传接口:
首先在app/router.js添加一个新的路由

创建一个新的:controller (app/controller/monitor)

看一下接收后的结果☟

记入日志文件:

下一步就是讲错误记入日志。实现的方法可以自己用fs写,也可以借助log4js这样成熟的日志库。
当然在eggjs中是支持我们定制日志那么我么你就用这个功能定制一个前端错误日志好了。
在/config/config.default.js中增加一个定制日志配置

在/app/controller/monitor.js中添加日志记录:

最后实现的效果:

八、Webpack插件实现SourceMap上报

Webpack插件实现SourceMap上传

谈到异常分析最重要的工作其实是将webpack混淆压缩的代码还原。

创建Webpack插件:

/source-map/plugin(文件位置)

加载webpack插件:

webpack.config.js(文件位置)

添加读取sourcemap读取逻辑:
在apply函数中增加读取sourcemap文件的逻辑/plugin/uploadSourceMapWebPlugin.js

实现http上传功能:

服务器端添加上传接口:/backend/app/router.js(文件位置)

添加sourcemap上传接口:/backend/app/controller/monitor.js

最终效果:
执行webpack打包时调用插件sourcemap被上传至服务器。

九、解析ErrorStack

解析ErrorStack

考虑到这个功能需要较多逻辑,我们准备把他开发成一个独立的函数并且用Jest来做单元测试:
先看一下我们的需求☟

搭建Jest框架:

首先创建一个/utils/stackparser.js文件☟

在同级目录下创建测试文件stackparser.spec.js
以上需求我们用Jest表示就是

整理如下:
下面我们运行Jest

npx jest stackparser --watch

显示运行失败,原因很简单因为我们还没有实现对吧。

下面我们就实现一下这个方法☟

反序列Error对象:

首先创建一个新的Error对象 将错误栈设置到Error中。
然后利用error-stack-parser这个npm库来转化为stackFrame

运行效果如下☟

解析ErrorStack:
下一步我们将错误栈中的代码位置转换为源码位置

我们再用Jest测试一下☟

这时我们再看一下结果:

这样一来测试就通过啦~

将源码位置记入日志:

记录完成后,我们再来看一下运行效果:

结束了这一步,我们的ErrorStack工作就完成了。

十、两种开源框架

需要运用的两种开源框架

Fundebug:
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 
自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有阳光保险、荔枝FM、掌门1对1、核桃编程、微脉等众多品牌企业。

Sentry:
Sentry 是一个开源的实时错误追踪系统,可以帮助开发者实时监控并修复异常问题。
它主要专注于持续集成、提高效率并且提升用户体验。
Sentry 分为服务端和客户端 SDK,前者可以直接使用它家提供的在线服务,也可以本地自行搭建;
后者提供了对多种主流语言和框架的支持,包括 React、Angular、Node、Django、RoR、PHP、Laravel、Android、.NET、JAVA 等。
同时它可提供了和其他流行服务集成的方案,例如 GitHub、GitLab、bitbuck、heroku、slack、Trello 等。
目前公司的项目也都在逐步应用上 Sentry 进行错误日志管理。

十一、总结

截止到目前为止,我们把前端异常监控的基本功能算是形成了一个MVP(最小化可行产品)。
后面需要升级的还有很多,对错误日志的分析和可视化方面可以使用ELK。
发布和部署可以采用Docker。对eggjs的上传和上报最好要增加权限控制功能。

最后

欢迎关注「前端瓶子君」,回复「交流」加入前端交流群!

欢迎关注「前端瓶子君」,回复「算法」自动加入,从0到1构建完整的数据结构与算法体系!

在这里(算法群),你可以每天学习一道大厂算法编程题(阿里、腾讯、百度、字节等等)或 leetcode,瓶子君都会在第二天解答哟!

另外,每周还有手写源码题,瓶子君也会解答哟!

》》面试官也在看的算法资料《《

“在看和转发”就是最大的支持

从0到1,Vue大牛的前端搭建——异常监控系统相关推荐

  1. 从无到有<前端异常监控系统>落地

    从无到有<前端异常监控系统>落地 参考文章: (1)从无到有<前端异常监控系统>落地 (2)https://www.cnblogs.com/1wen/p/7942608.htm ...

  2. 直播回顾丨神策数据王朋:如何搭建一套高可用的前端异常监控系统?

    本文根据神策数据资深前端研发工程师王朋在神策「大数据技术系列直播课」第二季"前端专题"第四讲的直播整理. 本次分享主要分为三大部分:前端异常监控概述,异常监控的背景意义,以及做一个 ...

  3. 前端代码异常监控—window.onerror

    我是开发微信图文页一名普通的码农.近期加班加点上线非常重要的的广告功能: 底部的广告区域有关注公众号的按钮,用户点击之后就会给广告主带来粉丝,给文章所有者带来广告收入.某天,码农心血来潮,想了解一下每 ...

  4. vue项目使用chimee搭建网络监控环境---直播m3u8

    一.安装chimee插件,以下三步 npm i chimee npm i chimee-plugin-controlbar npm i chimee-plugin-danmu 二.在需要的文件中引入c ...

  5. 前端异常监控调研总结

    前端异常监控 一.异常监控系统 二.异常情况 三.异常表现分类 四.Web前端监控分类 五. 监控分类解析 六 错误分类和捕获 七 小程序异常监控 八 前端异常上报方式 一.异常监控系统 前端和后端处 ...

  6. [转] 前端异常监控解决方案研究

    前端监控包括行为监控.异常监控.性能监控等,本文主要讨论异常监控.对于前端而言,和后端处于同一个监控系统中,前端有自己的监控方案,后端也有自己等监控方案,但两者并不分离,因为一个用户在操作应用过程中如 ...

  7. Sentry异常监控方案部署-前端攻略

    原文首发于我的个人博客: https://lonhon.top/ 凡事只要有可能出错,那就一定会出错 对于任何一个项目而言,本地测试肯定做不到100%覆盖,而且,我们也不能保证用户能按照我们的预期进行 ...

  8. 前端代码异常日志收集与监控

    在复杂的网络环境和浏览器环境下,自测.QA测试以及 Code Review 都是不够的,如果对页面稳定性和准确性要求较高,就必须有一套完善的代码异常监控体系,本文从前端代码异常监控的方法和问题着手,尽 ...

  9. 调用后台接口返回报错前端隐藏提示_前端异常监控解决方案研究(转)

    前端监控包括行为监控.异常监控.性能监控等,本文主要讨论异常监控.对于前端而言,和后端处于同一个监控系统中,前端有自己的监控方案,后端也有自己等监控方案,但两者并不分离,因为一个用户在操作应用过程中如 ...

最新文章

  1. mysql8.0.28忘记密码
  2. python book.save_2.3.1. 将二进制数据存为文件:saveBinDataToFile
  3. 2021年信息系统项目管理师考试大纲
  4. Python Cookbook(第3版)中文版:15.17 传递文件名给C扩展
  5. pg日期转周_postgresql 存储过程函数:时间戳与日期字符串相互转换
  6. BubbleSort 优化后的冒泡排序算法
  7. 精通Android自定义View(十二)绘制圆形进度条
  8. 2.Java 面试题整理(基础篇二)
  9. 打印服务器打印文件,通过打印服务器远程打印文件
  10. http server类型和版本号_nginx 简单隐藏服务器版本号
  11. C#制作QQ截图的自动框选功能的个人思路(二)设置Hook
  12. Verilog语言与数字系统设计
  13. 63. 无阻塞加载脚本
  14. 将 Entity Framework、LINQ 和 Model-First 用于 Oracle 数据库
  15. JVM监控及诊断工具GUI篇之Arthas(五):其他指令
  16. 算法精解----3、单链表
  17. Windows桌面分享程序设计
  18. 音频功放的失真的原因分析及测量
  19. 【Unity】 HTFramework框架(十七)Hotfix热更新模块
  20. 幼儿课外活动游戏_幼儿园户外活动游戏大全

热门文章

  1. dnf服务器未响应怎么解决方法,win7系统dnf经常未响应怎么办|win7 dnf假死的解决方法...
  2. 简易聊天室(未完善版)
  3. 彻底解决windows标题栏字体变小问题
  4. golang之文件读写/复制/断点续传
  5. DevOps的个人见解
  6. 甲骨文转换器在线转换 v1.0 官方版​
  7. html中的content作用,meta name= content=的作用详细介绍
  8. Ubuntu 15 安装搜狗输入法
  9. APIO2018爆零记
  10. 在React中使用FontAwesome字体