监控是提高故障处理能力和保障服务质量必需的一环,它需要负责的内容包括:及时上报错误、收集有效信息、提供故障排查依据。
综上所述,我们的监控平台强调实时性和全面性。为了保证实时性,错误发生时就尝试上报,并且在监控面板可以实时的展现出来,以及有及时的告警机制。全面性是指收集的信息全面,包括用户信息、环境信息和错误信息等,因此监控平台包括记录型监控和捕捉型监控。
当捕捉型监控捕捉到错误后,我们根据错误信息定位用户,再通过记录型监控还原该错误发生的场景,从而复现问题并及时定位解决。这个过程我们称之为场景还原法。
本监控平台就是通过收集监控数据,使用场景还原法来解决问题。它将支撑系统处理过的所有记录和错误按照时间顺序展示。通过场景还原的列表,我们可以还原出指定用户在浏览页面过程中发生的所有事情及其先后顺序,从而判断问题发生的时机和环境。
假设以下场景:
PM:BD反馈用户在购物车刷不出来啦!
RD:什么?我试试!我这里可以看到的呀
PM:商户反馈,店里有的用户可以有的用户不行
RD:别急,告诉我shopId和打不开的用户的账号,我去监控平台上看一下
PM:xxx
RD在监控面板上使用场景还原功能,调出了该用户的所有信息记录。发现该用户是从菜品详情页进入的购物车,而再查看正常的用户都不是从这个入口进的,定位到是菜品详情页跳购物车的部分有问题,并立刻进行了修复
在以上这种用户可能有多种操作的场景中,场景还原法可以针对特定用户,还原其完整的操作路径和页面上发生的所有事情,帮助复现问题。
另外,一些非必现的问题,常常是由于不同机型或环境引起的,也可以在场景还原中复现问题的发生环境予以判断。
本文主要介绍点餐终端技术组监控平台HUNT的前端SDK的实践经验,仍有许多需要改进的地方,欢迎大家拍砖,帮助我们改进。
如图所示,我们的监控平台HUNT,分为前端SDK、Web层支撑系统和监控面板三大部分。
前端SDK运行在前端页面中,收集监控数据上报到支撑系统里,作为监控面板上查询的数据源。
就前端SDK来说,可以分为数据模块、数据处理模块、上报模块三大部分,其中数据模块包括各具体监控数据模块和环境数据模块:
SDK里采用单例模式,包括各监控模块、环境模块和上报模块。
每个具体监控模块获取上报模块实例进行上报,上报模块内部保证同时只会有一个上报请求。
事件的监听都在捕获阶段进行,防止因为事件冒泡被阻止而遗漏信息。
环境模块收集以下环境信息:项目配置信息、Web环境数据、JsBridge环境数据。
其它的一些诸如UA、ISP等Web层可以获取的信息由Web层获取。
该模块暴露init和getEnv方法。
采取单请求上报的方式,每个用户同时只会有一条上报请求,每次将当前记录到的监控信息列表一起上报,成功后再继续上报。
上报结束之前的新上报记录都存在Localstorage,收到成功消息后删除已上报数据,继续上报,不成功的记录保留在Localstorage。此处需注意对Localstorage存储的上限做好控制。
在当前没有数据正在上报的情况下触发上报,尝试将当前Localstorage的数据和新数据全部上报,若上报记录过多,则分条发送。全部发送完或上报失败,本次上报结束。
HTTPS页面被劫持后页面资源无法获取,劫持者无利可图的情况下会降低劫持的动力。
若仍被劫持,前端资源未到达本地,也无法完成上报,只能从网络层去监控。
由于美团点评平台已经全量切了HTTPS,因此该模块不在本监控系统中。
不过之前本团队做过对HTTP域下的劫持检测,其检测思路为请求Node层指定域名下的样本HTML或JavaScript资源,对比返回结果是否符合预期。
资源完整性检查模块的任务是记录页面加载了哪些资源,并进行上报。
当我们排查问题时,可以查看当前页面已经加载成功了哪些资源及其加载顺序,排除因为某些资源没有加载或者加载顺序不当而引起错误的情况。
资源加载完整性检查的上报时机分四类,每次将开始监听到触发上报之间所有记录到的已加载资源一起上报,减少上报请求数:
内存中维护一个已加载资源的数组,每次上报后删除已上报的资源记录。
Window上error事件代理,过滤Window本身的error。
根据标签类型判断资源类型,src或href为资源地址。
为了捕获跨域JavaScript的错误,需要在相应资源标签上添加crossorigin属性。
同样采用XMLHttpRequest加hook方式实现。
open时记录接口URL,send后根据status判断,接口调用失败时进行上报。
XMLHttpRequest.prototype.open = function open(method, url, bool) { monitor.originXHR.open.apply(this, [method, url, bool]); // get something... // this.ajaxUrl = url; } XMLHttpRequest.prototype.send = function send(_data) { const self = this; this.addEventListener('readystatechange', () => { if (self.readyState === 4) { if (self.status !== 200 && self.status !== 304 && this.ajaxUrl !== REPORT_URL) { // filter urls // report error info // ... // monitor.reporter.report(dataTypes.API_ERROR, error); } } }, false); monitor.originXHR.send.apply(this, [_data]); };
过滤掉SDK本身的上报地址(防止上报失败引起循环上报)和一些其它需要忽略的接口地址。
注意,接口访问URL时可能是一个相对路径,建议补全协议和domain。
监听Window上的error事件,过滤事件代理的error。
监听Window上捕获阶段的click事件,记录点击相关数据。
业务代码中可以为比较关注的元素添加data属性,每次点击将会上报被点击元素的指定属性、附加信息和DOMPath帮助定位该元素。
记录用户交互信息可以明确问题发生时,该场景下用户的具体操作路径,结合环境数据、资源加载记录和错误数据,整个问题场景就一目了然了。
SDK的接入方式分为以下两种:
为了满足功能需要,当前监控平台v1的引入方式是将压缩后的SDK代码直接引入到被监控页面的head中,并由业务代码初始化配置项目名称等。该步操作可以借助webpack的插件来帮助完成,减轻业务组接入的复杂度。
后续改进方向考虑采用:核心基础库+loaders/plugins 的方式,将必须先加载的SDK代码引入在head中,其余代码等页面加载完成后再异步添加。
HUNT系统上线后,已经完全覆盖点餐终端组的活跃Web项目,进行监控数据的多维度上报。接下来工作重点是对收集到的数据进行有效的分析和利用。
目前大部分现有的监控工具只关注捕捉型监控这部分,记录型监控是缺失的。相应的,以记录型监控作为支撑的场景还原功能也是无法做到的。这类型的监控系统只能做到发现错误,但是对于错误定位帮助甚微。
接入本监控系统后,不但能在监控面板上实时的看到多种错误信息,还能根据错误发生的上下文,包括页面加载的过程,其中用户做了哪些操作,访问了哪些API等,按时间顺序排列来完成场景还原。再结合该错误发生的环境数据,复现问题和定位问题变的非常容易。
当收到故障反馈后,对一些偶发的问题,或者用户操作复杂的问题等,可以直接通过监控面板了解情况,省去了大量的沟通成本,我们的故障反馈速度和能力也有极大的提高。
以上就是我们终端团队监控平台前端SDK部分的实践分享,欢迎大家批评指正,有好的建议也希望能提出来帮助我们改进。我们后续将不断优化,也将继续与大家保持讨论。耐心看到这里的读者,表示十二万分的感谢!
回答“思考题”、发现文章有错误、对内容有疑问,都可以来微信公众号(美团点评技术团队)后台给我们留言。我们每周会挑选出一位“优秀回答者”,赠送一份精美的小礼品。快来扫码关注我们吧!