一步一步搭建前端监控系统:如何记录用户行为?

摘要: 通过记录用户行为快速复制BUG场景。

作者:逐步建立前端监控系统(备选)用户行为统计和监控文章(如何快速定位在线问题)

Fundebug授权转载后,版权归原作者所有。

前端监控系统系列博客逐步构建:

前端监控系统逐步构建:JS错误监控篇前端监控系统逐步构建:如何将网页截图上报?前端监控系统逐步构建:接口请求异常监控篇前端监控系统逐步构建:如何定位前端线上问题?前端监控系统逐步构建:如何记录用户行为?

背景:市场上有很多监控系统,其中大部分是收费的,这一定是小型前端项目的痛点。另一个主要原因是,虽然功能是通用的,但它可能无法满足我们自己的需求, 所以自给自足可能是一个很好的方法。

这是构建前端监控系统的第二章,主要介绍如何统计js报错,跟着我一步一步做,你也可以建立自己的前端监控系统。

目前已在线运行Demo: 前端监控系统

代码和讲解都放在这篇文章里:监控系统介绍及代码

假如真的觉得部署麻烦,Demo该系统可提供 7天 监控,我将长期维护:一键部署

长期以来,前端在线项目对前端程序猿来说完全是一个黑盒子。一旦项目启动,我们就不知道用户在我们的项目中做了什么,跳到哪里,是否报告了错误。一旦在线用户出现问题,我们就无法复制它,我们就会意识到什么是绝望。无论多么困难,问题总是在哪里等着你。所以,如果我们能把在线项目变成一个白盒子,让我们知道用户在网上做了什么,复制就不再困难了,这对前端程序员来说是一件好事。

接下来我要写的是一个重要的功能,因为它大大提高了我解决问题的能力,对我的工作影响很大。

截止到现在,来看看我已经完成了哪些功能:

PV/UV统计报告,js错误的上报和分析,接口统计报告,页面截屏的统计上报。那么,再补上今天要写的“用户点击行为的上报”,我们基本上就能够分析出一个用户在页面上干了什么。

1、如何记录在线用户的行为?

在线用户的基本行为包括: 访问页面,点击行为,请求界面行为,js报错行为,这几点基本上能够清楚的记录下用户在线上的所有行为。当然还包括:资源加载行为,滚动页面行为,元素进入用户视野等等行为,这些是更为细节的行为统计,也许会在以后进行完善,但是以上的四种行为已经可以完成我们的统计需求。

访问页面,js我们已经有了报错行为。接下来,让我们来看看如何统计点击和请求界面的行为。

点击行为// 用户行为日志,继承日志基类MonitorBaseInfo function BehaviorInfo(uploadType,behaviorType,className,placeholder,inputValue,tagName,innerText) setCommonProperty.apply(this); this.uploadType = uploadType; this.behaviorType = behaviorType; this.className = utils.b ** EncodeUnicode(className); this.placeholder = utils.b ** EncodeUnicode(placeholder); this.inputValue = utils.b ** EncodeUnicode(inputValue); this.tagName = tagName; this.innerText = utils.b ** EncodeUnicode(encodeURIComponent(innerText)); }/** * 用户行为记录监控 * @param project 项目细节 */ function recordBehavior(project) // 行为记录开关 if (project && project.record && project.record == 1) // 记录行为前,检查一下url记录是否发生变化 记录是否发生变化checkUrlChange(); / 记录用户点击元素的行为数据document.onclick = function (e) var className = ""; var placeholder = ""; var inputValue = ""; var tagName = e.target.tagName; var innerText = ""; if (e.target.tagName != "svg" && e.target.tagName != "use") className = e.target.className; placeholder = e.target.placeholder || ""; inputValue = e.target.value || ""; innerText = e.target.innerText.replace(/s*/g,behaviorInfo); }behaviorInfo); } } };

先来看看点击行为的代码。其实很简单,就是重写document的onclick方法,然后保存相应元素的属性、内容等,但我们花了这么多精力保存这么多日志,只是为了简单地记录用户的点击行为,这太浪费了。因此,这种点击行为统计将被添加到未来的保留分析中,以实现无埋点记录日志的功能,使我们的监控系统更加强大和丰富。保留分析将参考GrowingIo,有兴趣可以了解一下。

我们需要记录元素className,tagName,innerText等等,我们需要足够的内容来确定用户点击了哪个按钮。这种方法相对较弱,将在未来写保留分析功能时得到改进,但足以满足我们的要求。

请求界面行为// 界面请求日志继承日志基类MonitorBaseInfo function HttpLogInfo(uploadType,url,status,statusText,statusResult,currentTime) setCommonProperty.apply(this); this.uploadType = uploadType; this.httpUrl = utils.b ** EncodeUnicode(url); this.status = status; this.statusText = statusText; this.statusResult = statusResult; this.happenTime = currentTime; }/** *要求对页面接口进行监控 */ function recordHttpLog() // 监听ajax状态 function ajaxEventTrigger(event) var ajaxEvent = new CustomEvent(event,{ detail: this }); window.dispatchEvent(ajaxEvent); } var oldXHR = window.XMLHttpRequest; function newXHR()(){ var realXHR = new oldXHR(); realXHR.addEventListener('abort',function () ajaxEventTrigger.call(this,'ajaxAbort&#三九;false); realXHR.addEventListener('error',function () ajaxEventTrigger.call(this,'ajaxError&#三九;false); realXHR.addEventListener('load',function () ajaxEventTrigger.call(this,'ajaxLoad&#三九;false); realXHR.addEventListener('loadstart',function () ajaxEventTrigger.call(this,'ajaxLoadStart&#三九;false); realXHR.addEventListener('progress',function () ajaxEventTrigger.call(this,'ajaxProgress&#三九;false); realXHR.addEventListener('timeout',function () ajaxEventTrigger.call(this,'ajaxTimeout&#三九;false); realXHR.addEventListener('loadend',function () ajaxEventTrigger.call(this,'ajaxLoadEnd&#三九;false); realXHR.addEventListener('readystatechange',function() { ajaxEventTrigger.call(this,'ajaxReadyStateChange&#三九;false); return realXHR; } window.XMLHttpRequest = newXHR; window.addEventListener('ajaxLoadStart',function(e) { var currentTime = new Date().getTime() setTimeout(function () { var url = e.detail.responseURL; var status = e.detail.status; var statusText = e.detail.statusText; if (!url || url.indexOf(HTTP_UPLOAD_LOG_API) != -1) return; var httpLogInfo = new HttpLogInfo(HTTP_LOG, url, status, statusText, "发起请求", currentTime); httpLogInfo.handleLogInfo(HTTP_LOG, httpLogInfo); }, 2000) }); window.addEventListener('ajaxLoadEnd', function(e) { var currentTime = new Date().getTime() var url = e.detail.responseURL; var status = e.detail.status; var statusText = e.detail.statusText; if (!url || url.indexOf(HTTP_UPLOAD_LOG_API) != -1) return; var httpLogInfo = new HttpLogInfo(HTTP_LOG, url, status, statusText, "请求返回", currentTime); httpLogInfo.handleLogInfo(HTTP_LOG, httpLogInfo); });​ }

让我们来看看接口行为统计的代码先,本来这个我想单独拿出来说一说的,但是现在么有那么多时间把它相关的功能开发出来,所以只写了一个简版的。

接口行为的统计包括: 发起请求,接收请求,接收状态,请求时长, 通过前端对接口的统计和分析,我们是可以观察出线上接口的质量,同时也能够对前端的逻辑做出相应的调整,已达到页面加载的最佳效果。 数据库字段定义都在分析后台的项目里, 可以直接去看。

首先,我们要监听页面的ajax请求, 如上所示,写了一段监听ajax请求的代码(我是在网上扒下来的 thanks), 可以监听到页面上所有的ajax请求,对整个ajax请求过程进行了原子性分析,我们可以监听到请求过程中任何一个时段的事件,非常好用。 但是,有一点非常重要, 如果你的项目里边用的是fetch请求数据的话, 那么这些监听就无效了。 因为fetch代码是浏览器注入的, 肯定先用监控代码执行,然后你再监听ajax就一点用都没有了。 所以你需要在写好ajax监听之后,重写fetch代码, 这样就可以生效了。好了,这部分并不是这篇幅的重点,我们就说到这里。

二、如何查询线上用户的行为

终于,我们把剩下的两种行为记录都成功上传了,那么该如果把他们都查询出来呢。我们先来看一下页面上我查询出来的结果。

因为屏幕太小,无法展示所有的记录,记录信息包含:行为名称,行为发生时间, 行为发生页面, 错误信息, 错误截图, 以及用户自定义上传截图的时机。

说到这里有几个小问题需要注意。

因为是用Js做探针,记录日志的时候很难保证每次记录都可以把用户的userId插入进去所以我们给每个用户都定义一个customerKey来做区分,如果用户不卸载app和清理app的缓存, customerKey将保持不变在查询用户的行为记录的时候,需要先查询出用户所有的customerKey(可能有多个),再用customerKey进行查询,便可以得到准确的结果。三、如何分析线上用户的行为

其实我们做了这么多,记录了这么多,就是为了这个目的:分析行为,快速定位问题。

那么我们如何定位问题呢,我可以举例说明一下:

JS报错阻断行为,我们可以看到发生错误的前后行为,就能够快速准确定位问题。

复杂的链接跳转发生了错误。有些错误是前端页面会经过复杂的跳转,回退之后才发生的,就算测试人员也很难测试出这种问题,因为线上的用户的任何行为都有可能出现。往往我们知道的只是他在最后停留的页面发生了错误。 如此,经过我们排查行为日志, 就能够复现出用户的行为, 从而复现BUG接口异常。 正常情况下,前端的接口都会设置超时时间的, 但是呢, 后台接口排查发现正常, 而前端就是无 ** 常执行, 这种问题没有显示的错误现象,而线上的反馈并不能够准确,前端只能背锅了。 而日志记录是可以把请求发出时间和返回时间记录下来, 是否超时,看一眼就知道。线上的用户根本就不会反馈异常, 他们能做的只是把最后一眼能看到的东西告诉你。 天知道他们之前经历了什么步骤。 最终的结果是,前端有问题,然后背锅,哈哈。

总之, 我们知道用户在页面上干了什么, 便不再担心问题出现, 遇见问题也不会再手忙脚乱了。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了20亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!

Copyright ©2021 All rights reserved | 粤ICP备2021138463号-3

扫码免费用

源码支持二开

申请免费使用

在线咨询