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

  • 作者:一步一个脚印一个坑
  • 原文:搭建前端监控系统(备选)用户行为统计和监控篇(如何快速定位线上问题)

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

一步一步搭建前端监控系统系列博客:

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

背景: 市面上的监控系统有很多,大多收费,对于小型前端项目来说,必然是痛点。另一点主要原因是,功能虽然通用,却未必能够满足我们自己的需求, 所以我们自给自足也许是个不错的办法。

这是搭建前端监控系统的第二章,主要是介绍如何统计js报错,跟着我一步步做,你也能搭建出一个属于自己的前端监控系统。

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

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

如果实在嫌部署麻烦,Demo系统可以提供 7天 的监控量,我会长期维护:一键部署

一直以来, 前端上线的项目,对于前端程序猿来说,完全是一个黑盒子。 项目一旦上线,我们完全不知道用户在我们的项目里边做了什么,跳转到哪里,是不是报错了。一旦线上用户出现问题,而我们又无法复现的时候,才能体会到什么叫绝望。 不管多么艰难,问题总是会在哪里等着你。所以,如果我们可以把线上的项目变成一个白盒子,让我们能够知道用户在线上干了什么,复现不再困难了,对前端程序员来说,是不是一件好事呢。

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

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

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

一、如何记录线上用户的行为

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

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

点击行为

// 用户行为日志,继承于日志基类MonitorBaseInfofunction BehaviorInfo(uploadType, behaviorType, className, placeholder, inputValue, tagName, innerText) {setCommonProperty.apply(this);this.uploadType = uploadType;this.behaviorType = behaviorType;this.className = utils.b64EncodeUnicode(className);this.placeholder = utils.b64EncodeUnicode(placeholder);this.inputValue = utils.b64EncodeUnicode(inputValue);this.tagName = tagName;this.innerText = utils.b64EncodeUnicode(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, "");// 如果点击的内容过长,就截取上传if (innerText.length > 200) innerText = innerText.substring(0, 100) + "... ..." + innerText.substring(innerText.length - 99, innerText.length - 1);innerText = innerText.replace(/\s/g, '');}var behaviorInfo = new BehaviorInfo(ELE_BEHAVIOR, "click", className, placeholder, inputValue, tagName, innerText);behaviorInfo.handleLogInfo(ELE_BEHAVIOR, behaviorInfo);}}};

我们先来看一下点击行为的代码,其实很简单,就是重写一下document的onclick方法,然后把相应的元素的属性,内容等等保存起来, **但是,**我们费了这么大的力气保存了如此多的日志,就为了简单的记录一下用户的点击行为,实在太浪费了。 所以,这个点击行为统计会被添加到未来的留存分析当中去,到时候能够实现无埋点记录日志的功能,让我们的监控系统更加的强大和丰富。留存分析会参考GrowingIo, 有兴趣可以了解一下。

我们需要记录下元素的className, tagName, innerText等等,我们需要足够的的内容才能够确定用户点击的是哪个按钮。这种方式比较弱智,将会在以后写留存分析功能的时候进行完善一下,但是目前足以满足我们的要求了。

请求接口行为

// 接口请求日志,继承于日志基类MonitorBaseInfofunction HttpLogInfo(uploadType, url, status, statusText, statusResult, currentTime) {setCommonProperty.apply(this);this.uploadType = uploadType;this.httpUrl = utils.b64EncodeUnicode(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累计处理了10亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!

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

  1. 一步一步搭建前端监控系统:如何将网页截图上报?

    摘要: 通过录屏或者截图,快速复现BUG场景. 作者:一步一个脚印一个坑 原文:搭建前端监控系统(备选)Js截图上报篇 Fundebug经授权转载,版权归原作者所有. PS:本文关于Fundebug录 ...

  2. 搭建前端监控系统(二)JS错误监控篇

    背景:市面上的监控系统有很多,大多收费,对于小型前端项目来说,必然是痛点.另一点主要原因是,功能通用,却未必能够满足我们自己的需求, 所以我们自给自足. 这是搭建前端监控系统的第二章,主要是介绍如何统 ...

  3. 搭建前端监控系统(四)接口请求异常监控篇

    背景:市面上的监控系统有很多,大多收费,对于小型前端项目来说,必然是痛点.另一点主要原因是,功能虽然通用,却未必能够满足我们自己的需求, 所以我们自给自足也许是个不错的办法. 这是搭建前端监控系统的第 ...

  4. 带api的php探针,从零开始搭建前端监控系统(一)——web探针sdk

    前言 本系列文章旨在讲解如何从零开始搭建前端监控系统. 项目已经开源 项目地址: 您的支持是我们不断前进的动力. 喜欢请start!!! 喜欢请start!!! 喜欢请start!!! 本文是该系列第 ...

  5. 呀!原来这就是前端监控系统

    大厂技术  高级前端  Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 在刚开始学前端的时候,那时候开发的应用总是在用户的设备中出现一些报错,开发者只知道这个型号的 ...

  6. 【Web技术】1480- 呀!原来这就是前端监控系统

    在刚开始学前端的时候,那时候开发的应用总是在用户的设备中出现一些报错,开发者只知道这个型号的设备出现这个问题,但对其他信息却全然不知,比如说其他操作系统.其他设备型号.其他页面会有这个报错吗,这个报错 ...

  7. 简单三步教会你在前端监控平台:安装小程序、uni-app探针(详细教程)

    Webfunny现在支持微信小程序.uni-app的监控探针了,两个平台安装探针的方式很相似. 一.微信小程序探针安装 (1)首先创建一个微信小程序项目 (2)项目生成后,复制探针代码.在小程序项目的 ...

  8. 让我们一起写一个前端监控系统吧!

    CSDN话题挑战赛第2期 参赛话题:前端技术分享 项目介绍 我们基于Vue2.利用vue-plugin实现项目级别的npm包监控报错,并专为Vue项目设计了监控中台 核心监控插件开箱即用,用户可灵活选 ...

  9. 不用羡慕BAT,自己手工也能搭建伪基站监控系统

    本文讲的是不用羡慕BAT,自己手工也能搭建伪基站监控系统,编者按:伪基站是个很烦人的东西.基于海量移动终端用户,近两年BAT3在国内搭建了强大的伪基站监控系统,在打击犯罪上贡献不少.这篇文章中,作者将 ...

  10. Telegraf+InfluxDB+Grafana快速搭建实时监控系统 监控postgresql

    Telegraf+InfluxDB+Grafana快速搭建实时监控系统  监控postgresql 转载于:https://www.cnblogs.com/gaoyuechen/p/10081026. ...

最新文章

  1. 别在 Java 代码里乱打日志了,这才是正确的打日志姿势!
  2. Python3比较运算符
  3. 20145228 《信息安全系统设计基础》第0周学习总结
  4. 数字农业WMS库存操作重构及思考
  5. iOS屏幕旋转 浅析
  6. 【HDOJ】2389 Rain on your Parade
  7. 赚钱真的要抓住风口,抓住风口猪都能飞
  8. 建立可视化决策平台,“数据化”首当其冲! 1
  9. Java基础篇:算术赋值运算符
  10. 【算法07】求子数组的最大和
  11. 算法基本知识,入门必备
  12. 计算机学院三下乡,重庆理工大学计算机学院”三下乡“教师情牵故乡
  13. windows系统服务器如何修改登录密码
  14. Linux使用详解(进阶篇)
  15. 企微裂变定位裂变,实现粉丝增长,提高客户留存率。
  16. Golang zip流式解析器
  17. JS的 验证组织机构的合法性
  18. 高考排名liuseroj.picp.io
  19. 阿里云安装数据库mysql数据库服务器_阿里云CentOs服务器 安装与配置mysql数据库...
  20. css设置笼罩层透明(兼容所有浏览器)

热门文章

  1. curry化 js_认识 科里化(curry)——JS函数式编程
  2. PPT画图-颜色搭配
  3. 将word选择题转换成Excel
  4. Flickr网站架构分析
  5. 夏新N820/N821 recovery刷入教程附MT6577专用刷机工具SP_Flash_Tool_v3.1308.0.125
  6. 当在浏览器中输入 Google.com 并按下回车之后发生了什么?
  7. 红楼梦诗词全集---留一份吧,太珍贵了!!
  8. 嵌入式系统ARM期末总复习
  9. H3CNE V7.0 视频教程
  10. ssb门限_ssb单边带的产生方法