如果你是一位前端工程师,那你一定不止一次去解决一些顽固的线上问题,你也曾想方设法复现用户的bug,结果可能都不太理想......
如何定位前端线上问题,一直以来,都是很头疼的问题,因为它发生于用户的一系列操作之后。
错误的原因可能源于机型,网络环境,接口请求,复杂的操作行为等等,在我们想要去解决的时候很难复现出来,自然也就无法解决。当然,这些问题并非不能克服,让我们来一起看看如何去监控并定位线上的问题吧。
如果:你还是一个手无寸铁的前端小白吗?你想拥有一套属于自己的监控系统吗?跟着我一步步操作做,你也能搭建出一个属于自己的前端监控系统。
首页概览图
一、JS Error 监控功能 (数据概览)
如果每天都去盯着前端的报错数据,真的很耗费精力,而且很难看出是今天发生的,还是一直存在的报错。其实前端项目每天都会有些报错,比如:script error 。我们既不能控制,也不会影响我们的业务,只能让它一直存在。所以我们的前端应用,每天都会有一定数量的报错数据。只要日活量不会波动太大,那么报错数据就会比较平稳,所以我选择跟7天前的报错数据进行比较,如果出现大幅上升,那么就需要我对这个项目进行关注了,而不是每天查看具体的报错数据。
前端项目报错统计图
对于前端应用来说,Js错误的发生直接影响前端应用的质量。对前端异常的监控是整个前端监控系统中的一个重要环节。前端异常包含很多种情况:1. js编译时异常(开发阶段就能排);2. js运行时异常;3. 加载静态资源异常(路径写错、资源服务器异常、CDN异常、跨域);4. 接口请求异常等。这一篇我们只介绍Js运行时异常。
监控流程:监控错误 -> 搜集错误 -> 存储错误 -> 分析错误 -> 错误报警-> 定位错误 -> 解决错误
首先,我们应该对Js报错情况有个大致的了解,这样才能够及时的了解前端项目的健康状况。所以我们需要分析出一些必要的数据,如下图所示:
前端项目报错的分析数据
那么我们该如何去监控这些数据呢?其实主要用到下边三种方法:
1)重写window.onerror 方法, 大家熟知,监控JS错误必然离不开它,有人对他进行了测试测试介绍感觉也是比较用心了。
2)重写console.error方法,为什么要重写这个方法,我不能够给出明确的答案,如果App首次向浏览器注入的Js代码报错了,window.onerror是无法监控到的,所以只能重写console.error的方式来进行捕获,也许会有更好的办法。待window.onerror成功后,此方法便不再需要用了。
3)重写
window.onunhandledrejection方法。当你用到Promise的时候,而你又忘记写reject的捕获方法的时候,系统总是会抛出一个叫 Unhandled Promise rejection. 没有堆栈,没有其他信息,特别是在写fetch请求的时候很容易发生。所以我们需要重写这个方法,以帮助我们监控此类错误
下边是就是做JS错误监控代码,大家可以参考一下:
// 重写console.error, 可以捕获更全面的报错信息
var oldError = console.error;
console.error = function (tempErrorMsg) {
var errorMsg = (arguments[0] && arguments[0].message) || tempErrorMsg;
var lineNumber = 0;
var columnNumber = 0;
var errorObj = arguments[0] && arguments[0].stack;
if (!errorObj) {
siftAndMakeUpMessage("console_error", errorMsg, WEB_LOCATION, lineNumber, columnNumber, "CustomizeError: " + errorMsg);
} else {
siftAndMakeUpMessage("console_error", errorMsg, WEB_LOCATION, lineNumber, columnNumber, errorObj);
}
return oldError.apply(console, arguments);
};
// 重写 onerror 进行jsError的监听
window.onerror = function(errorMsg, url, lineNumber, columnNumber, errorObj) {
jsMonitorStarted = true;
var errorStack = errorObj ? errorObj.stack : null;
siftAndMakeUpMessage("on_error", errorMsg, url, lineNumber, columnNumber, errorStack);
};
// 重写 onunhandledrejection 对未处理的rejection错误进行捕获处理
window.onunhandledrejection = function(e) {
var errorMsg = "";
var errorStack = "";
if (typeof e.reason === "object") {
errorMsg = e.reason.message;
errorStack = e.reason.stack;
} else {
errorMsg = e.reason;
errorStack = "";
}
siftAndMakeUpMessage("on_error", errorMsg, WEB_LOCATION, 0, 0, "UncaughtInPromiseError: " + errorStack);
}
封装简易的Ajax
为了将这些数据上传到我们的服务器,我们总不能每次都用xmlHttpRequest来发送ajax请求吧,所以我们需要自己封装一个简单的Ajax。
this.ajax = function(method, url, param, successCallback, failCallback) {
var xmlHttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xmlHttp.open(method, url, true);
xmlHttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
var res = JSON.parse(xmlHttp.responseText);
typeof successCallback == 'function' && successCallback(res);
} else {
typeof failCallback == 'function' && failCallback();
}
};
xmlHttp.send("data=" + JSON.stringify(param));
}
二、JS Error 详细信息解析
统计JS Error的目的,一、是为了了解线上项目的健康状况,二、是为了分析错误,帮助我们查找问题之所在,并且解决它。所以,如何定位线上的问题,并解决问题,是我们现在要讨论的重点。下面我们需要对几个关键点进行分析,先看一下总体的分析图:
JS错误分析结果图
① 某种错误发生的次数——发生次数跟影响用户是成正比的, 如果发生次数跟影响用户数量都很高,那么这是一个比较严重的bug, 需要立即解决。反之, 如果次数很多,影响用户数量很少。说明这种错误只发生在少量设备中,优先级相对较低,可以择时对该类机型设备进行兼容处理。当然,ip地址访问次数也能说明这个问题。
② 页面发生了哪些错误——这个有利于我们缩小问题的范围,方便我们排查。
③ 错误堆栈——这点不用说,是定位错误最重要的因素。正常情况下,代码都是被压缩的,所以我在后台解析并截取出错代码附近的一部分代码,进行展示,排查错误。PS: 可以根据sourceMap解析压缩混淆代码的具体位置和代码片段,想法很不错,后期我会加上,目前已经完成测试版本。另外,代码虽然被压缩,但是依然很轻松定位到出错的位置,如下图所示。
sourceMap解析源码
④ 设备信息——当错误发生是,分析出用户当时使用设备的浏览器信息,系统版本,设备机型等等,能够帮我们快速的定位到需要兼容的设备,进而提升解决问题的效率。
⑤ 用户足迹——通过记录用户的具体步骤,可以清晰了解到用户出错前后时间内发生的事情,对解决问题也有很大的帮助。如下图:
用户行为记录
三、JS报错的实时监控与报警
既然我们已经具有了搜集js报错和分析报错的能力了,那么我们也可以做到Js报错实时监控,以及实时预警了,这样可以防范线上事故于未然,及时的制止线上事故的持续发生, 减少损失。
如上图所示,展示了从当前时间向前推算24小时,每小时报错数量。另外展示了7天前同一时间段的报错数量,如果你的项目健康稳定,那么在相同时间段的报错数量应该不会相差太大。如果出现相差太大的情况发生,说明线上出现了问题,此刻应该发出警告,避免线上事故的发生。demo上暂未加上警告功能,但是原理清楚了,后边自然水到渠成。
最后这个功能应该很容易理解,及时的发布警报,能够让你更快知道前端的问题。
至此,我们的JS错误统计功能就完成了,你学会了吗?