我的GitHub
0%

无星的前端之旅(七)—— PC端Web错误日志收集1

背景

线上报错,啥也不知道,无法复现束手无策,客户开喷,研发背锅

这种事情,u1s1,大家都遇到过吧

解决方式就是有个日志收集上报的地方去查,查什么时候,什么时间,什么环境,出了什么错误,在某些程度能不那么被动

选型

是不是以为我是要说用哪家,实际上是准备自己写。。

免费的不放心,付费的买不起
但这里还是列出几家
fundebug
sentry

怎么做?

1.了解需要采集的指标
2.收集的方式
3.上报的方式
4.上报的时机
5.如何解析
6.告警

1.了解需要采集的数据指标

这里可以参考一些付费的服务的采集指标,比如上面提到的fundebug,sentry,看看人家都收集啥。

在了解以后,根据自身平台业务的需要,自行采集。

比如我没有那些花里胡哨的需求,我只采集了如下信息:

1
2
3
4
5
6
7
8
9
appId:我自己的业务数据,用来标识哪个App出了问题
type:错误类型
message:错误抛出的message
stack:错误堆栈信息
line:出错行
column:出错列
url:sourceMap后出错的js地址
userAgent:用户的环境,什么浏览器,什么版本等等
time:出错的世界

实际上你还可以采集更多,但我的业务只需要这些了。

2.收集

2.1 收集上报策略核心

这里我引用参考文章中《自研多端错误收集平台》,贝贝的一句话作为核心思路:“差异化采集,格式化上报!”
在不同平台使用不同的采集方式。处理成统一的方式最后上报。
在我落地的表现上就是,不同平台写不同包去处理,最后统一格式上传

1
2
3
vue,xxx-error-vue
react,xxx-error-react
wechat,xxx-error-wechat

2.2 错误的类型

1
2
3
4
1.同步的脚本错误
2.异步的脚本错误
3.网络错误
4.资源加载型错误

我这里只捕获1,2,3

2.3 收集的方式

2.3.1 自动收集方式兜底

自动采集的方式是一定要有的。

这是个兜底策略,在没能手动上报的时候去抓住一些钩子抛出来的错误。

对于运行在浏览器环境的JavaScript代码来说,浏览器会抛出几个钩子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
window.onerror = function (message, source, line, column, error) {
//错误捕获1与 window.addEventListener('error') 二选一即可
}
window.addEventListener('error', event => {
//错误捕获2,与 window.onerror 二选一即可
})
window.addEventListener('unhandledrejection', event => {
//错误捕获3,未实现Promise.reject()
// 默认实现,以免控制台红色警告
if (process.env.NODE_ENV === 'production') { event.preventDefault(); }
})
function networkHandle(): void {
//错误捕获4,网络请求错误
let originSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
console.log('send', arguments);
this.addEventListener('loadend', () => {
console.log('loadend')
if (this.status !== 200) {
//网络请求挂了,捕获
}
})
originSend.apply(this, arguments);
};

}

对于额外的框架提供的错误,例如vue,它有着自己的Vue.config.errorHandler机制

1
2
3
Vue.config.errorHandler = function (error: Error, vm: Object, info: any) {
//错误捕获处理
}

2.3.2 手动上报方式

这个方式也是一定要有的,它可以用来人为捕获一些业务/技术错误

1
2
3
function notify(error: Error): void {
//这里面就写点格式化处理和上报
}

2.4.2 如何进行错误格式化

上面也说了,核心思想是

1
差异化采集,格式化上报

那么提到格式化,就不得不提到这个背景了。

在不同浏览器不同框架上,抛出来的error不一样!

比如:Vue.config.errorHandler中拿到的error是Vue处理后的信息,你无法很直观的拿到colum和line。

这里就不得不提到一个库了TraceKit

他的作用就是,格式化error,使得不同环境下的error输出相同格式的错误!

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as TraceKit from 'tracekit'
function notify(error: Error): void {
// 计算堆栈
let stack = TraceKit.computeStackTrace(error)
// stack = {name:'xx',mode:'xx',message:'xxx',stack:[{
// 出错的js地址
// url:'xxx',
// line:0,
// column:0,
//},{xx},{xx}]}
//取第一个是因为一般第一个item中的url是真实报错的业务js
let tmpStack = get(stack, ['stack', '0'])
// 格式化stack
let errorInfo: ErrorInfo = createErrorInfo(stack.name,stack.mode,stack.message,tmpStack)
//格式化成string
let result: String = formatErrorInfo(errorInfo)
//这是上报,原因见下面
let image = new Image()
image.src = baseUrl + result
}

3.上报的方式

这里我使用请求图片get请求的方式上报

1
2
3
4
5
6
function notify(error){
//formatErrorInfo是自定义的格式化方法,后文会写做了什么
let result : String = formatErrorInfo(error)
let image = new Image()
image.src = baseUrl + result
}

为什么?

1.图片请求没有跨域错误

2.使用图片发送get请求,上报信息,由于浏览器对图片有缓存,同样的请求,图片只会发送一次,避免重复上报

3.get请求简单

4.上报的时机

较好的方式:制定本地策略,合并请求,统一上传,节省流量也减少服务端压力。

我就没那么多想法,出错就上报,直接一梭子往上怼就完事了,没到那个量级,也没那么多错误。后面也许会优化吧。

5.如何解析

挖个坑

6.告警

暂未做

7.可视化

我们有elk,直接把数据格式化打到elk上就可以了。

但是目前没有没有想到好的方式去做sourceMap解析。

曾经设想过写kibana插件去完成这个操作,但是我整了半天都没跑起来,有点难受。

我的设想:
1.kibana提供插件的形式去调取elk的存储查询功能,这是最完美的解决方式了。
2.自己写页面,调取elk的查询接口。但阻塞点是elk的查询接口如何使用http调用?
3.自己去存错误,不用elk,但这太蠢了。不太想这么做。

8.写个demo?

啥时候有空啥时候补一个。。。

demo

参考文章

前端早早聊-自研多端错误收集平台
前端异常监控系统的落地

我是阿星,阿星的阿,阿星的星!