从0到1搭建前端异常监控系统(Vue + Webpack + Node.js + Egg.js + Jest)(上)

简介: 从0到1搭建前端异常监控系统(Vue + Webpack + Node.js + Egg.js + Jest)

您将Get的技能


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


  • 编写错误上报逻辑


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


  • 编写webpack插件自动上传sourcemap


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


  • 利用Jest进行单元测试


工作流程


  1. 收集错误


  1. 上报错误


  1. 代码上线打包将sourcemap文件上传至错误监控服务器


  1. 发生错误时监控服务器接收错误并记录到日志中


  1. 根据sourcemap和错误日志内容进行错误分析


一、 前端异常监控平台解决的问题


前端异常监控系统就是为了解决前端系统上线后的稳定性问题。一旦前端系统上线,发生运行异常造成页面阻塞,操作不流畅甚至无法打开网页的状况。我们需要通过技术手段收集、上报、分析异常才能保证前端项目稳定运行。


二、异常收集


首先先看看如何捕获异常。


1.  JS异常


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


setTimeout(() => {
  console.log('1->begin')
  error
  console.log('1->end')
})
setTimeout(() => {
  console.log('2->begin')
  console.log('2->end')
})


网络异常,图片无法展示
|


上面的例子我们用setTimeout分别启动了两个任务,虽然第一个任务执行了一个错误的方法。程序执行停止了。但是另外一个任务并没有收到影响。


其实如果你不打开控制台都看不到发生了错误。好像是错误是在静默中发生的。


下面我们来看看这样的错误该如何收集。


1.1 try-catch


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


setTimeout(() => {
  try {
    console.log('1->begin')
    error
    console.log('1->end')
  } catch (e) {
    console.log('catch',e)
  }
})


网络异常,图片无法展示
|


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


function fun1() {
  console.log('1->begin')
  error
  console.log('1->end')
}
setTimeout(() => {
  try {
    fun1()
  } catch (e) {
    console.log('catch',e)
  }
})


网络异常,图片无法展示
|


控制台中打印出的分别是错误信息和错误堆栈。


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


function fun1() {
  console.log('1->begin')
  error
  console.log('1->end')
}
try {
  setTimeout(() => {
    fun1()
  })
} catch (e) {
  console.log('catch', e)
}


网络异常,图片无法展示
|


大家注意运行结果,异常并没有被捕获。


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


1.2 window.onerror


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


function fun1() {
  console.log('1->begin')
  error
  console.log('1->end')
}
window.onerror = (...args) => {
  console.log('onerror:',args)
}
setTimeout(() => {
  fun1()
})


网络异常,图片无法展示
|


  • onerror返回值


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


1.3 监听error事件


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


其实onerror固然好但是还是有一类异常无法捕获。这就是网络异常的错误。比如下面的例子。


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


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

addEventListener就是


window.addEventListener('error', args => {
    console.log(
      'error event:', args
    );
    return true;
  }, 
  true // 利用捕获方式
);


运行结果如下:


网络异常,图片无法展示
|


1.4 Promise异常捕获


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


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


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


new Promise((resolve, reject) => {
  error()
})
// 增加异常捕获
  .catch((err) => {
  console.log('promise catch:',err)
});


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


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


网络异常,图片无法展示
|


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


window.addEventListener("unhandledrejection", e => {
  throw e.reason
});


1.5 async/await异常捕获


const asyncFunc = () => new Promise(resolve => {
  error
})
setTimeout(async() => {
  try {
    await asyncFun()
  } catch (e) {
    console.log('catch:',e)
  }
})


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

try/catch捕获。


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


小结


异常类型 同步方法 异步方法 资源加载 Promise async/await
try/catch ✔️ ✔️
onerror ✔️ ✔️
error事件监听 ✔️ ✔️ ✔️
unhandledrejection事件监听 ✔️ ✔️


实际上我们可以将unhandledrejection事件抛出的异常再次抛出就可以统一通过error事件进行处理了。


最终用代码表示如下:


window.addEventListener("unhandledrejection", e => {
  throw e.reason
});
window.addEventListener('error', args => {
  console.log(
    'error event:', args
  );
  return true;
}, true);


2. Webpack工程化项目中捕获异常


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


比如:


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


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


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


sourceMap是什么


简单说,sourceMap就是一个文件,里面储存着位置信息。


仔细点说,这个文件里保存的,是转换后代码的位置,和对应的转换前的位置。


那么如何利用sourceMap对还原异常代码发生的位置这个问题我们到异常分析这个章节再讲。


3. Vue捕获异常


3.1 创建工程


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


# 安装vue-cli
npm install -g @vue/cli
# 创建一个项目
vue create vue-sample
cd vue-sample
npm i
// 启动应用
npm run serve


为了测试的需要我们暂时关闭eslint 这里面还是建议大家全程打开eslint


在vue.config.js进行配置


module.exports = {   
  // 关闭eslint规则
  devServer: {
    overlay: {
      warnings: true,
      errors: true
    }
  },
  lintOnSave:false
}


我们故意在src/components/HelloWorld.vue


<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  mounted() {
    // 制造一个错误
    abc()
  }
};
</script>
```html
然后在src/main.js中添加错误事件监听
```js
window.addEventListener('error', args => {
  console.log('error', error)
})


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


网络异常,图片无法展示
|


3.2 handleError


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


我们在src/main.js


Vue.config.errorHandler = function (err, vm, info) {
  console.log('errorHandle:', err)
}


运行结果结果:


网络异常,图片无法展示
|


4. React捕获异常


4.1 创建项目


npx create-react-app react-sample
cd react-sample
yarn start


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


import React ,{useEffect} from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
  useEffect(() => { 
    // 发生异常
    error()
  }); 
  return (
    <div className="App">
      // ...略...
    </div>
  );
}
export default App;


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


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


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


网络异常,图片无法展示
|


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
1263 1
|
移动开发 前端开发 JavaScript
Vue与React两大前端框架的主要差异点
以上就是Vue和React的主要差异点,希望对你有所帮助。在选择使用哪一个框架时,需要根据项目的具体需求和团队的技术栈来决定。
758 83
|
JavaScript 前端开发 API
|
JavaScript 前端开发 编译器
Vue与TypeScript:如何实现更强大的前端开发
Vue.js 以其简洁的语法和灵活的架构在前端开发中广受欢迎,而 TypeScript 作为一种静态类型语言,为 JavaScript 提供了强大的类型系统和编译时检查。将 Vue.js 与 TypeScript 结合使用,不仅可以提升代码的可维护性和可扩展性,还能减少运行时错误,提高开发效率。本文将介绍如何在 Vue.js 项目中使用 TypeScript,并通过一些代码示例展示其强大功能。
535 22
|
前端开发 JavaScript 数据可视化
58K star!这个让网页动起来的JS库,前端工程师直呼真香!
Anime.js 是一款轻量级但功能强大的JavaScript动画引擎,它能够以最简单的方式为网页元素添加令人惊艳的动效。这个项目在GitHub上已经获得58,000+星标,被广泛应用于电商页面、数据可视化、游戏开发等场景。
692 8
|
资源调度 JavaScript 前端开发
前端开发必备!Node.js 18.x LTS保姆级安装教程(附国内镜像源配置)
本文详细介绍了Node.js的安装与配置流程,涵盖环境准备、版本选择(推荐LTS版v18.x)、安装步骤(路径设置、组件选择)、环境验证(命令测试、镜像加速)及常见问题解决方法。同时推荐开发工具链,如VS Code、Yarn等,并提供常用全局包安装指南,帮助开发者快速搭建高效稳定的JavaScript开发环境。内容基于官方正版软件,确保合规性与安全性。
15527 23
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
1643 14
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
1053 0
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
839 6