传统的前端监控原理分为异常捕获和异常上报。通常使用onerror
捕获前端错误:javascript
window.onerror = (msg, url, line, col, error) => { console.log('onerror') // TODO }
可是onerror
事件没法捕获到网络异常的错误(资源加载失败、图片显示异常等),例如img
标签下图片url 404 网络请求异常的时候,onerror
没法捕获到异常,此时须要监听unhandledrejection
。前端
window.addEventListener('unhandledrejection', function(err) { console.log(err) })
捕获的异常如何上报?经常使用的发送形式主要有两种:vue
function report(error) { var reportUrl = 'http://xxxx/report' new Image().src = reportUrl + '?error=' + error }
sentry是一套开源的强大的前端异常监控上报工具,官网地址:https://sentry.io,官方提供了如何搭建sentry服务,此处略过安装流程,直接使用已有的服务。java
针对vue,sentry官方推荐使用raven配合sentry进行异常捕获和上报。而在vue中,vue提供了错误捕获方法vue error handler
,官方也推荐使用错误追踪服务 sentry 并经过vue error handler
选项提供了官方支持。jquery
raven是sentry官方针对vue推荐的插件,yarn安装raven-js便可。ajax
$ yarn add raven-js
初始化引入Vue、Raven、RavenVue便可,sentry能主动监听上报错误。promise
import Raven from 'raven-js' import RavenVue from 'raven-js/plugins/vue' const dsn = 'https://<key1>@sentry.io/<key2>' Raven.config(dsn).addPlugin(RavenVue, Vue).install()
对于一些其余信息,如提示日志等,没法自动捕获,须要手动进行上报。网络
log (data = null, type = 'error', options = {}) { // 添加面包屑 Raven.captureBreadcrumb({ message: data, category: 'manual message' }) // 异常上报 if (data instanceof Error) { Raven.captureException(data, { level: type, logger: 'manual exception', tags: { options: options } }) } else { Raven.captureException('error', { level: type, logger: 'manual data', extra: { data: data, options: this.options, date: new Date() } }) } }
针对上述内容,封装异常上报类Report,使用单例模式,避免监控类重复实例化。工具
/**
* by csxiaoyao
* 2019.03.17
* sunjianfeng@csxiaoyao.com
*/
import Raven from 'raven-js' import RavenVue from 'raven-js/plugins/vue' class Report { static dsn = 'https://<key1>@sentry.io/<key2>' constructor (Vue, options = {}) { if (process.env.NODE_ENV === 'production') { // TODO } this.Vue = Vue this.options = options } /** * 单例模式 */ static getInstance (Vue, options) { if (!(this.instance instanceof this)) { this.instance = new this(Vue, options) this.instance.install() this.instance.registerError() } return this.instance } /** * init */ install () { Raven.config(Report.dsn, { release: '1.0.0', environment: 'production' // whitelistUrls: [/localhost/, /test\.oa\.com/] }).addPlugin(RavenVue, this.Vue).install() // 记录用户信息 Raven.setUserContext({ user: this.options.user || '' }) // 设置全局tag标签 Raven.setTagsContext({ environment: this.options.env || '' }) } /** * 注册全局错误处理 */ registerError () { // 监听error window.onerror = (msg, url, line, col, error) => { console.log('onerror') if (msg !== 'Script error.' && !url) { return true } setTimeout(() => { let data = {} col = col || (window.event && window.event.errorCharacter) || 0 data.url = url data.line = line data.col = col data.error = error if (&& error.stack) { data.msg = error.stack.toString() } this.log(data) }, 0) return true } // 监听promise window.addEventListener('unhandledrejection', err => { console.log('unhandledrejection') setTimeout(() => { this.log(JSON.stringify