前端监控SDK开发分享 (2)

在以上这个场景中,我们能够提高前端排查问题的能力,甚至能辅助后端同学。在大部分时候,出现bug,很可能第一时间首先是找到前端做反馈,前端是排查问题的先头部队。当我们有这样的前端监控系统之后,不至于每次遇到问题手足无措,解决问题的时间也会快许多。

【具体字段一览】

前端监控SDK开发分享

确定好了要收集哪些信息,接下来就需要去实现客户端SDK,它能够在业务项目中自动收集数据上报给服务端。

三、客户端SDK(探针)相关原理和API

所谓探针,是因为我们的SDK要依托于监控的前端项目的运行环境,在其运行环境的底层API中加入探针函数来收集信息,下面分享WEB和微信小程序SDK实现的主要原理和使用的API。

3.1 WEB

下图是SDK主要使用的Web API,通过这几个API我们就能分别获取到:页面性能信息、资源性能信息、ajax信息、错误信息。

前端监控SDK开发分享

3.1.1 Performance

通过performance.timing可以拿到页面首次加载的性能数据,dns、tcp、白屏时间等,而在最新的标准中performance.timing已经被废弃,因此我们也改造为使用performance.getEntriesByType('navigation')。这里的白屏时间可能和实际真正的用户感官的白屏时间是有差异的,仅供参考。

通过new PerformanceObserver监听器,我们可以监听所有资源(css,script,img,ajax等)加载的性能数据:加载时间,响应大小,http协议版本(http1.1/http2)等。而后我们需要通过一个数组去管理资源性能数据,在完成数据上报后,清空数组。

3.1.2 fetch/xmlHttpRequest

由于浏览器并没有提供一个统一的API使我们能够收集到ajax请求和响应数据,并且不管我们是用axois还是使用其他的http请求库,他们都是基于fetch和xmlHttpRequest实现的。因此只能通过重写fetch和xmlHttpRequest,并在对应的函数和逻辑中插入自定义代码,来达到收集的目的。相关的文章很多,这里就不再细说了。

let _fetch = fetch; window.fetch = function () { // custom code return _fetch .apply(this, arguments) .then((res) => { // custom code return res; }) }; 3.1.3 window.onerror | unhandledrejection | console.error | 以及框架自带的监听函数

最后这几个API都是收集js相关错误信息的。需要注意两个问题:

一是onerror会获取不到跨域的script错误,解决方案也很简单:为跨域的script标签设置crossorigin属性,并且需要静态服务器为当前资源设置CORS响应头。

二是代码压缩后的报错信息需要通过sourceMap文件解析出源代码对应的行列和错误信息,sourceMap本身是一种数据结构,存储了源代码和压缩代码的关系数据,通过解析库能够很轻松转换它们。但如何自动化管理和操作sourceMap文件才是前端监控系统核心需要解决的问题。这里就需要结合企业内部的静态资源发布系统和前端监控系统,来解决低效率的手动打包上传问题。

3.2 微信小程序

微信小程序底层使用js实现,有着它自己的一套生命周期,也提供了全局的API。通过重写它的部分全局函数和相关API我们能获取到:网络请求、错误信息、设备和版本信息等。由于微信小程序的加载流程是由微信APP控制的,js等资源也被微信内部托管,因此和web不同,我们没有办法获取到web中performance能获取到的页面和资源加载信息。下图是SDK主要使用的API

前端监控SDK开发分享

3.2.1 App和Component

通过重写全局的App函数,绑定onError方法监听错误,重写它的onShow方法执行小程序启动时SDK需要的逻辑。通过重写Component的onShow方法,可以在页面组件切换时执行我们的路径收集和执行上报等逻辑。

// SDK初始化函数 init(){ this.appMethod = App; this.componentMethod = Component; const ctx = this; //重写微信小程序Component Component = (opts) => { overrideComponent(opts, ctx); ctx.componentMethod(opts); }; //重写微信小程序App App = (app) => { overrideApp(app, ctx); ctx.appMethod(app); }; } //注意ctx是sdk的this overrideComponent(opts, ctx) => { const compOnShow = opts.methods.onShow; opts.methods.onShow = function(){ // do something //注意这里的this是实际调用方 compOnShow.apply(this, arguments) } }) overrideApp(app, ctx) => { const _onError = app.onError || function () {}; const _onShow = app.onShow || function () {}; app.onError = function (err) { reportError(err, ctx); return _onError.apply(this, arguments); }; app.onShow = function () { //do something return _onShow.apply(this, arguments); }; }) 3.2.2 重写wx.request

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfxsd.html