搭建前端监控系统(备选)用户行为统计和监控篇(如何快速定位线上问题)

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

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

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

============================================================================

www.webfunny.cn前端监控提供只需要简单几步就可以搭建一套属于自己的前端监控系统,快来试试吧^ _ ^

============================================================================

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

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

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

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


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

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

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

点击行为:

//用户行为日志,继承于日志基类MonitorBaseInfo
  functionBehaviorInfo(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 项目详情
   */
  functionrecordBehavior(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等等,我们需要足够的的内容才能够确定用户点击的是哪个按钮。这种方式比较弱智,将会在以后写留存分析功能的时候进行完善一下,但是目前足以满足我们的要求了。


请求接口行为:

//接口请求日志,继承于日志基类MonitorBaseInfo
  functionHttpLogInfo(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;
  }

/**
   * 页面接口请求监控
   */
  functionrecordHttpLog() {
    //监听ajax的状态
    functionajaxEventTrigger(event) {
      var ajaxEvent = newCustomEvent(event, {
        detail: this});
      window.dispatchEvent(ajaxEvent);
    }
    var oldXHR =window.XMLHttpRequest;
    functionnewXHR() {
      var realXHR = newoldXHR();
      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);
      returnrealXHR;
    }

    window.XMLHttpRequest =newXHR;
    window.addEventListener('ajaxLoadStart', function(e) {
      var currentTime = newDate().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 = newDate().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代码, 这样就可以生效了。好了,这部分并不是这篇幅的重点,我们就说到这里。

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

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

搭建前端监控系统(备选)用户行为统计和监控篇(如何快速定位线上问题)第1张

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

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

1. 因为是用Js做探针,记录日志的时候很难保证每次记录都可以把用户的userId插入进去

2. 所以我们给每个用户都定义一个customerKey来做区分,如果用户不卸载app和清理app的缓存,customerKey将保持不变

3. 在查询用户的行为记录的时候,需要先查询出用户所有的customerKey(可能有多个),再用customerKey进行查询,便可以得到准确的结果。

三、如何分析线上用户的行为

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

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

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

搭建前端监控系统(备选)用户行为统计和监控篇(如何快速定位线上问题)第2张

2. 复杂的链接跳转发生了错误。有些错误是前端页面会经过复杂的跳转,回退之后才发生的,就算测试人员也很难测试出这种问题,因为线上的用户的任何行为都有可能出现。往往我们知道的只是他在最后停留的页面发生了错误。 如此,经过我们排查行为日志, 就能够复现出用户的行为, 从而复现BUG

3. 接口异常。 正常情况下,前端的接口都会设置超时时间的, 但是呢, 后台接口排查发现正常, 而前端就是无法正常执行, 这种问题没有显示的错误现象,而线上的反馈并不能够准确,前端只能背锅了。 而日志记录是可以把请求发出时间和返回时间记录下来, 是否超时,看一眼就知道。

4. 线上的用户根本就不会反馈异常, 他们能做的只是把最后一眼能看到的东西告诉你。 天知道他们之前经历了什么步骤。 最终的结果是,前端有问题,然后背锅,哈哈。

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

免责声明:文章转载自《搭建前端监控系统(备选)用户行为统计和监控篇(如何快速定位线上问题)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇zbar配置Yapi部署下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

专业术语常用名词缩写中英文对照

A:Actuator 执行器A:Amplifier 放大器A:Attendance员工考勤A:Attenuation衰减AA:Antenna amplifier 开线放大器AA:Architectural Acoustics建筑声学AC:Analogue Controller 模拟控制器ACD:Automatic Call Distribution 自动...

我们是如何做好前端工程化和静态资源管理

随着互联网的发展,我们的业务也日益变得更加复杂且多样化起来,前端工程师也不再只是做简单的页面开发这么简单,我们需要面对的十分复杂的系统性问题,例如,业务愈来愈复杂,我们要如何清晰地梳理;团队人员愈来愈多,我们要如何更好地进行团队协作;功能愈来愈多,我们要如何保证页面的性能不至于下降,等等。所有的这些都可以归结为如何提升开发体验和性能问题。 提升开发体验...

前端学习之html

<b>  定义粗体文本 <big> 定义大号字体 <em> 定义着重文字 <i> 定义斜体字 <small> 定义小号字 <strong> 定义加重语气 <sub>  定义下标字 <sup> 定义上标字 <ins> 定义插入字 <del>...

性能测试基本概念 聚合报告指标分析

一、基本概念 1.测试计划是使用 JMeter 进行测试的起点,它是其它 JMeter 测试元件的容器。 2.线程组:代表一定数量的并发用户,它可以用来模拟并发用户发送请求。实际的请求内容在Sampler中定义,它被线程组包含。可以在“测试计划 ->添加->线程组”来建立它,然后在线程组面板里有几个输入栏:线程数、Ramp-Up Period(...

90%的前端都会踩的坑

【建议收藏】90%的前端都会踩的坑,你中了吗? 写在前面 移动开发时代,前端同学刚刚送别了让人头秃的IE浏览器,却发现憧憬已久的移动互联网时代并不是想象中那般美好。各种棘手的系统兼容问题和浏览器兼容问题怎么也让人高兴不起来。作为一名工作不足3年的前端程序媛,始终相信好记性不如烂笔头。每次在项目开发过程中踩到的坑,都习惯性地记录了下来。昨日一瞥竟积少成多...

【使用 DOM】为DOM元素设置样式

1. 使用样式表 可以通过document.styleSheets属性访问文档中可用的CSS样式表,它会返回一组对象集合,这些对象代表了与文档管理的各个样式表。 每个样式表 都由一个CSSStyleSheet 对象代表,它提供了一组属性和方法来操作文档里的样式。 1.1 获得样式表的基本信息 第一步是获得定义在文档中的样式表的一些基本信息。 <!...