异常监控平台如何设计?
基本点
- 错误采集
- 上报
- 数据汇总&清洗
- 数据统计
- 可视化
- 告警
1.错误采集
常见的 JavaScript 错误
- 语法 错误
SyntaxError
一般来说在开发构建阶段就会被编译器捕获,如果生产需要捕获
SyntaxError
的话,需要使用分开的脚本去捕获<script>
// 要捕获语法错误,需要使用分开的 <script>
window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
</script>
<script>
const notdefined,
</script>监控代码和业务代码不能放在同一个
<script>
标签中,否则此时 onerror 还没生效:Can syntax errors be caught in JavaScript?
- 类型错误
TypeError
- 引用错误
ReferenceError
- 范围错误
RangeError
这些错误可以通过
window.onerror
捕获:window.onerror = function (message, source, lineno, colno, error) {
console.log('捕获到异常:', { message, source, lineno, colno, error })
}
// TypeError 可以捕获 ✅
const notdefined = 1
console.log(notdefined.a.b)
// ReferenceError 可以捕获 ✅
console.log(notdefined)
// RangeError 可以捕获 ✅
console.log(new Array(-1))
资源错误
资源错误一般指图片、script、css 加载错误,这些错误不能通过 window.onerror
捕获,需要使用 window.addEventListener
捕获:
<script>
// 资源错误,不能捕获 ❌
window.onerror = function (message, source, lineno, colno, error) {
console.log('捕获到异常:', { message, source, lineno, colno, error })
return true
}
// 图片、script、css加载错误,都能被捕获 ✅
window.addEventListener(
'error',
(error) => {
console.log('捕获到异常:', error)
},
true
)
</script>
<img src="https://yun.tuia.cn/image/kkk.png" />
<script src="https://yun.tuia.cn/foundnull.js"></script>
<link href="https://yun.tuia.cn/foundnull.css" rel="stylesheet" />
为什么
window.onerror
不能捕获资源错误,而window.addEventListener
可以捕获资源错误? 🚧 WIP
未捕获的 Promise 错误
<script>
// 全局统一处理Promise
window.addEventListener("unhandledrejection", function(e){
console.log('捕获到异常:', e);
});
fetch('https://wukaipeng.com/test')
</script>
React 错误
主要使用 componentDidCatch
方法捕获 React 错误:
import * as React from 'react';
class ErrorListening extends React.Component {
constructor(props) {
super(props);
}
componentDidCatch(error, info) {
console.log("error", error)
}
}
在项目中使用:
import React from "react";
<ErrorListening>
<App />
</ErrorListening>
Vue 错误
Vue 使用 app.config.errorHandler
配置全局错误处理函数:
app.config.errorHandler = (err, instance, info) => {
// handle error, e.g. report to a service
}
2. 上报
使用 px 的透明 GIF 图片上报错误:
- 为什么不使用 GET/POST/HEAD 上报错误?因为存在跨域问题,一般上报接口和当前业务都是不同域
- 为什么不使用 JS/CSS/TTF 其他资源上报呢?因为其他资源需要创建元素节点并插入到 DOM 中才会发送请求,而且 JS/CSS 会阻塞渲染主线程。图片只需要
new Image()
即可发送请求,也不会阻塞渲染主线程。 - 为什么不使用 PNG/JPEG/BMP 文件格式呢?首先 px 的图片体积是最小的合法图片,只需要透明色,不需要颜色,所以排除 JPEG,其次 GIF 比 PNG/BMP 更小。