===================代码展示================
监控系统地址: Demo地址
页面探针代码: GitHub地址
分析后台地址: GitHub地址
展示平台地址: GitHub地址
===================代码展示================
对于前端应用来说,Js错误的发生直接影响前端应用的质量。对Js异常的监控是整个前端监控系统中的一个重要环节。 那么如何做到对Js错误的监控呢?对搜集到的js错误,我们该如何去分析呢?分析的结果该如何展示呢?这些问题将直接关系到是否能够监控和分出去有价值的数据。
首先,我们应该对Js报错情况有个大致的了解,这样才能够及时的了解前端项目的健康状况。所以我们需要分析出一些必要的数据。
如:一段时间内,应用JS报错的走势(chart图表)、JS错误发生率、JS错误在PC端发生的概率、JS错误在IOS端发生的概率、JS错误在Android端发生的概率,以及JS错误的归类。
然后,我们再去其中的Js错误进行详细的分析,辅助我们排查出错的位置和发生错误的原因。
如:JS错误类型、 JS错误信息、JS错误堆栈、JS错误发生的位置以及相关位置的代码;JS错误发生的几率、浏览器的类型,版本号,设备机型等等辅助信息
一、JS Error 监控功能(数据预览)
为了得到这些数据,我们需要在上传的时候将其分析出来。在众多日志分析中,很多字段及功能是重复通用的,所以应该将其封装起来。
// 设置日志对象类的通用属性 ?function setCommonProperty() { ???this.happenTime = new Date().getTime(); // 日志发生时间 ???this.webMonitorId = WEB_MONITOR_ID; ????// 用于区分应用的唯一标识(一个项目对应一个) ???this.simpleUrl = ?window.location.href.split(‘?‘)[0].replace(‘#‘, ‘‘); // 页面的url ???this.customerKey = utils.getCustomerKey(); // 用于区分用户,所对应唯一的标识,清理本地数据后失效 ???this.pageKey = utils.getPageKey(); ?// 用于区分页面,所对应唯一的标识,每个新页面对应一个值 ???this.deviceName = DEVICE_INFO.deviceName; ???this.os = DEVICE_INFO.os + (DEVICE_INFO.osVersion ? " " + DEVICE_INFO.osVersion : ""); ???this.browserName = DEVICE_INFO.browserName; ???this.browserVersion = DEVICE_INFO.browserVersion; ???// TODO 位置信息, 待处理 ???this.monitorIp = ""; ?// 用户的IP地址 ???this.country = "china"; ?// 用户所在国家 ???this.province = ""; ?// 用户所在省份 ???this.city = ""; ?// 用户所在城市 ???// 用户自定义信息, 由开发者主动传入, 便于对线上进行准确定位 ???this.userId = USER_INFO.userId; ???this.firstUserParam = USER_INFO.firstUserParam; ???this.secondUserParam = USER_INFO.secondUserParam; ?} ?// JS错误日志,继承于日志基类MonitorBaseInfo ?function JavaScriptErrorInfo(uploadType, errorMsg, errorStack) { ???setCommonProperty.apply(this); ???this.uploadType = uploadType; ???this.errorMessage = encodeURIComponent(errorMsg); ???this.errorStack = errorStack; ???this.browserInfo = BROWSER_INFO; ?} ?JavaScriptErrorInfo.prototype = new MonitorBaseInfo();
封装了一个JsError对象JavaScriptErrorInfo,用以保存页面中产生的Js错误。其中,setCommonProperty用以设置所有日志对象的通用属性。
1)重写window.onerror 方法, 大家熟知,监控JS错误必然离不开它,有人对他进行了测试测试介绍感觉也是比较用心了
2)重写console.error方法,为什么要重写这个方法,我不能够给出明确的答案,如果App首次向浏览器注入的Js代码报错了,window.onerror是无法监控到的,所以只能以此方式来进行捕获,也许会有更好的办法,待window.onerror成功后,此方法便不再需要用了
下边是启动JS错误监控代码
/** ??* 页面JS错误监控 ??*/ ?function recordJavaScriptError() { ???// 重写console.error, 可以捕获更全面的报错信息 ???var oldError = console.error; ???console.error = function () { ?????// arguments的长度为2时,才是error上报的时机 ?????// if (arguments.length < 2) return; ?????var errorMsg = arguments[0] && arguments[0].message; ?????var url = WEB_LOCATION; ?????var lineNumber = 0; ?????var columnNumber = 0; ?????var errorObj = arguments[0] && arguments[0].stack; ?????if (!errorObj) errorObj = arguments[0]; ?????// 如果onerror重写成功,就无需在这里进行上报了 ?????!jsMonitorStarted && siftAndMakeUpMessage(errorMsg, url, 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(errorMsg, url, lineNumber, columnNumber, errorStack); ???}; ???function siftAndMakeUpMessage(origin_errorMsg, origin_url, origin_lineNumber, origin_columnNumber, origin_errorObj) { ?????var errorMsg = origin_errorMsg ? origin_errorMsg : ‘‘; ?????var errorObj = origin_errorObj ? origin_errorObj : ‘‘; ?????var errorType = ""; ?????if (errorMsg) { ???????var errorStackStr = JSON.stringify(errorObj) ???????errorType = errorStackStr.split(": ")[0].replace(‘"‘, ""); ?????} ?????var javaScriptErrorInfo = new JavaScriptErrorInfo(JS_ERROR, errorType + ": " + errorMsg, errorObj); ?????javaScriptErrorInfo.handleLogInfo(JS_ERROR, javaScriptErrorInfo); ???}; ?};
OK, 错误日志有了,该怎么计算错误率呢?
JS错误发生率 = JS错误个数(一次访问页面中,所有的js错误都算一次)/PV (PC,IOS,Android平台同理)
所以我们需要记下页面的PV记录
// 用户访问行为日志(PV) ???function CustomerPV(uploadType, loadType, loadTime) { ?????setCommonProperty.apply(this); ?????this.uploadType = uploadType; ?????this.loadType = loadType; ?// 用以区分首次加载 ?????this.loadTime = loadTime; // 加载时间 ???} ???CustomerPV.prototype = new MonitorBaseInfo(); ???/** ????* 添加一个定时器,进行数据的上传 ????* 3秒钟进行一次URL是否变化的检测 ????* 15秒钟进行一次数据的检查并上传 ????*/ ???var defaultLocation = window.location.href.split(‘?‘)[0].replace(‘#‘, ‘‘); ???var timeCount = 0; ???setInterval(function () { ?????// 如果是单页应用, 只更改url ?????var webLocation = window.location.href.split(‘?‘)[0].replace(‘#‘, ‘‘); ?????// 如果url变化了, 就把更新的url记录为 defaultLocation, 重新设置pageKey ?????if (defaultLocation != webLocation) { ???????recordPV(); ???????defaultLocation = webLocation; ?????} ?????// 循环5后次进行一次上传 ?????if (timeCount >= 5) { ???????var logInfo = localStorage[ELE_BEHAVIOR] || "" + ?????????localStorage[JS_ERROR] || "" + ?????????localStorage[CUSTOMER_PV] || ""; ???????if (logInfo) { ?????????utils.ajax("POST", HTTP_UPLOAD_LOG_INFO, {logInfo: logInfo}, function (res) { ???????????// 上传完成后,清空本地记录 ???????????if (res.code === 200) { ?????????????localStorage[ELE_BEHAVIOR] = ""; ?????????????localStorage[JS_ERROR] = ""; ?????????????localStorage[CUSTOMER_PV] = ""; ???????????} ?????????}) ???????} ???????timeCount = 0; ?????} ?????timeCount ++; ???}, 3000);
上边的代码我用了定时器,大概的意思是3秒进行一次URL变化的检查,15进行一次数据的检查,如果有数据就进行上传,并清空上一次的数据。为什么用定时器呢,因为在单页应用中,路由的切换和地址栏的变化是无法被监控的,我确实没有想到特别好的办法来监控,所以用了这种方式,如果有人有更好的办法,请给我留言,谢谢
到此,已经收集到了JS错误日志的大部分信息了,只需要将其上传,入库,再进行分析展现,就可以看到JS错误信息的预览效果,所以,我们再去部署一下后台代码。
下一章: 搭建前端监控系统(三)NodeJs服务器部署篇
为了将这些数据上传到我们的服务器,我们总不能每次都用xmlHttpRequest来发送ajax请求吧,
所以我们需要自己封装一个简单的Ajax
/** ????* ????* @param method ?请求类型(大写) ?GET/POST ????* @param url ????请求URL ????* @param param ??请求参数 ????* @param successCallback ?成功回调方法 ????* @param failCallback ??失败回调方法 ????*/ ???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错误日志收集篇
原文地址:https://www.cnblogs.com/warm-stranger/p/9417084.html