背景
线上报错,啥也不知道,无法复现束手无策,客户开喷,研发背锅
这种事情,u1s1,大家都遇到过吧
解决方式就是有个日志收集上报的地方去查,查什么时候,什么时间,什么环境,出了什么错误,在某些程度能不那么被动
选型
是不是以为我是要说用哪家,实际上是准备自己写。。
免费的不放心,付费的买不起
但这里还是列出几家
fundebug
sentry
怎么做?
1.了解需要采集的指标
2.收集的方式
3.上报的方式
4.上报的时机
5.如何解析
6.告警
1.了解需要采集的数据指标
这里可以参考一些付费的服务的采集指标,比如上面提到的fundebug,sentry,看看人家都收集啥。
在了解以后,根据自身平台业务的需要,自行采集。
比如我没有那些花里胡哨的需求,我只采集了如下信息:
appId:我自己的业务数据,用来标识哪个App出了问题
type:错误类型
message:错误抛出的message
stack:错误堆栈信息
line:出错行
column:出错列
url:sourceMap后出错的js地址
userAgent:用户的环境,什么浏览器,什么版本等等
time:出错的世界
实际上你还可以采集更多,但我的业务只需要这些了。
2.收集
2.1 收集上报策略核心
这里我引用参考文章中《自研多端错误收集平台》,贝贝的一句话作为核心思路:“差异化采集,格式化上报!”
在不同平台使用不同的采集方式。处理成统一的方式最后上报。
在我落地的表现上就是,不同平台写不同包去处理,最后统一格式上传
vue,xxx-error-vue
react,xxx-error-react
wechat,xxx-error-wechat
2.2 错误的类型
1.同步的脚本错误
2.异步的脚本错误
3.网络错误
4.资源加载型错误
我这里只捕获1,2,3
2.3 收集的方式
2.3.1 自动收集方式兜底
自动采集的方式是一定要有的。
这是个兜底策略,在没能手动上报的时候去抓住一些钩子抛出来的错误。
对于运行在浏览器环境的JavaScript代码来说,浏览器会抛出几个钩子
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机制
Vue.config.errorHandler = function (error: Error, vm: Object, info: any) {
//错误捕获处理
}
2.3.2 手动上报方式
这个方式也是一定要有的,它可以用来人为捕获一些业务/技术错误
function notify(error: Error): void {
//这里面就写点格式化处理和上报
}
2.4.2 如何进行错误格式化
上面也说了,核心思想是
差异化采集,格式化上报
那么提到格式化,就不得不提到这个背景了。
在不同浏览器不同框架上,抛出来的error不一样!
比如:Vue.config.errorHandler中拿到的error是Vue处理后的信息,你无法很直观的拿到colum和line。
这里就不得不提到一个库了TraceKit
他的作用就是,格式化error,使得不同环境下的error输出相同格式的错误!
使用方式
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请求的方式上报
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?
啥时候有空啥时候补一个。。。
网友评论