作为前端经常遇到线上报错却无法复现的情况,要是这个时候有错误监控能快速帮我们定位问题所在,再查找错误监控的相关资料尝试去实现一个自己的sdk。下面我以 错误监控 和 设备信息 两方面作为关注点去实现。 完整代码
错误监控
运行时报错
window.onerror = (msg,url,lineNo,columnNo,e) => {
// …上报错误
}
复制代码
promise reject 未被处理
window.addEventListener(‘unhandledrejection’,(event) => {
// 报错原因,当前路径,报错时间
const { message,config:{method,url} } = event.reason
// …上报错误
})
复制代码
重写原生的监听事件
// 保存原生的 addEventListener 事件
const originAddEventListener = EventTarget.prototype.addEventListener
// 重写原生的监听事件
EventTarget.prototype.addEventListener = (type,listener,options) => {
const wrappedListenner = (…args) => {
try {
return listener.apply(this,args)
} catch (error) {
const { name,message } = error
// …上报错误
throw error
}
}
return originAddEventListener.call(this,type,wrappedListenner,options)
}
复制代码
劫持 Vue.config.errorHandler
const vueErrorHandler = Vue.config.errorHandler
const wrapErrorHandler = function(err,vm,info) {
const componentRouteInfo = vm.{className};id-${id}, nodeName } } // 获取该元素下嵌套的子元素的中第一个元素的文字 function searchBottomNestChild(dom:any) { let current = dom while (current.firstChild) { current = current.firstChild } return current.nodeValue } 复制代码 设备相关信息 const pageLog = () => { const userAgent = navigator.userAgent let webview = '' if (userAgent.match(/(i[^;]+;( U;)? CPU.+Mac OS X/)) { webview = 'ios' } if (userAgent.match(/MicroMessenger/([^\s]+)/)) { webview = 'weixin' } if (userAgent.match(/QQ/([\d.]+)/)) { webview = 'qq' } // 获取网络相关的信息 const connection = navigator.connection return { logType:LogType.page, path:location.href, platform:navigator.platform, webview, connection } } 复制代码 发送数据 通过 new Image 方式创建的元素,只需要赋值 src 属性即可发送请求,无需插入文档中。 需要注意在拼接参数的时候,需要使用 encodeURIComponent 对值进行转移否则将 location.href 这类url作为值时会造成错误。 function parseJsonToString(dataJson) { if (!dataJson ) { dataJson = {} } var dataArr = Object.keys(dataJson).map(function(key) { return key + '=' + encodeURIComponent(dataJson[key]) }) return dataArr.join('&') } const logGif = (params) => { const upload = parseJsonToString(params) const img = new Image(1,1) img.src = 'https://view-error?' + upload } 复制代码 打包sdk文件 完成了基本的错误监控功能后,我们可以把这些文件打包成一个js文件,其他项目需要应用的时候通过 script 引入的方式直接使用即可。 webpack.config.js 的配置会比我们项目中的少很多,由于我是使用的 typescript + vue 的方式,配置如下: const path = require('path') const resolve = dir => path.resolve(__dirname, dir) module.exports = { entry:{ // sdk文件的主入口 'view-error':resolve('../src/utils/index.ts') }, output:{ path:resolve('../dist') }, resolve: { extensions:['.ts','.js'] }, module: { rules:[ // 处理 .ts 结尾的文件 { test: /.tsx?{query}'))
// 图片作为返回
const file = fs.readFileSync(‘upload/icon-image.gif’)
ctx.type = ‘image/gif’
ctx.body = file
}
复制代码
疑问和待优化
问题
目前是通过 vue-router 来监听页面跳转的。我试了下 window.addEventListener(‘popstate’,()=>{}) 和 window.addEventListener(‘hashchange’,()=>{}) 都监听不到 vue 页面路由的变化。js原生能否监听路由变化?
想记录单个用户的操作链路,如何将用户链路关联起来,通过同ip关联吗,
服务端存储的时候该怎么归类存储查询比较方便快捷,服务端这块不是很熟悉。
待优化
1前端发送数据的时候统一格式,将请求分为几类或者相应的等级。
2优化客户端采集的信息,以及一些报错信息的捕获。
3服务端相同信息归类存储,优化存储空间。
对前端有想法的小伙伴可以加入q群:1017810018一起探讨学习哦