目录
前言
为什么需要埋点系统
电影中
现实中
什么是埋点系统
埋点 SDK 开发
埋点数据收集分析
代理请求
代理 XMLHttpRequest
代理 Fetch
监听页面的 PVUV
异常捕获
RUNTIME ERROR
Script Error
Promise reject
资源加载异常
监听用户行为
页面路由变化
监听页面离开
SDK 架构
数据流
项目结构
参考
结尾
首页 web前端 js教程 初探埋点系统

初探埋点系统

Sep 15, 2020 pm 04:24 PM
javascript

初探埋点系统

相关学习推荐:javascript视频教程

前言

最近杂七杂八的事情比较多,难得抽出时间来弥补一下之前的系列,欠大家的埋点系列现在开始走起来

为什么需要埋点系统

电影中

前端开发攻城狮开开心心的 coding,非常自豪的进行了业务、UI 分离开发,各种设计模式、算法优化轮番上阵,代码写的 Perfect(劳资代码天下第一),没有 BUG,程序完美,兼容性 No.1,代码能打能抗质量高。下班轻松打卡,回家看娃。

现实中

实际上,开发环境与生产环境并不能等同,并且测试的过程再完善,依然会有漏测的情况存在。考虑到用户使用客户端环境、网络环境等等一系列的不确定因素存在。

所以在开发过程中一定要记得三大原则(我胡诌的

  1. 没有完美的代码,只有没发现的 BUG
  2. 绝对不要相信测试环境,没有一种测试环境都涵盖所有线上情况
  3. 如果线上没有一点反馈,不要怀疑,问题应该藏得很深、很深

什么是埋点系统

埋点就像城市中的摄像头,从产品的角度考虑,它可以监控到用户在我们产品里的行为轨迹,为产品的迭代、项目的稳定提供依据,WHO、WHEN、WHERE、HOW、WHAT 是埋点采集数据的基础维度

对前端开发而言,可以监控页面资源加载性能,异常等等,提供了页面体验和健康指数,为后续性能优化提供依据,及时上报异常和发生场景。从而能够及时修正问题,提高项目质量等。

埋点可以大概分为三类:

  1. 无痕埋点 - 无差别收集页面所有信息包括页面进出、事件点击等等,需要进行数据冲洗才能获取到有用信息
  2. 可视化埋点 - 根据生成的页面结构获取特定点位,单独埋点分析
  3. 业务代码手动埋点 - 根据具体复杂的业务,除掉上述两种不能涵盖的地方进行业务代码埋点

代码埋点 可视化埋点 无痕埋点
典型场景 无痕埋点无法覆盖到,比如需要业务数据 简单规范的页面场景 简单规范的页面场景,
优势 业务数据明确 开发成本低,运营人员可直接进行相关埋点配置 无需配置,数据可回溯
不足 数据不可回溯,开发成本高 不能关联业务数据,数据不可回溯 数据量较大,不能关联业务数据

大部分情况,我们可以通过无痕埋点收集到所有的信息数据,再配合可视化埋点,能够具体定位到某一个点位,这样大部分的埋点信息都据此分析出来。

在特殊情况下,可以多加上业务代码手动埋点,处理一下特别的场景(大部分情况是走强业务与正常的点击,刷新事件无关需要上报的信息)

埋点 SDK 开发

埋点数据收集分析

  • 事件基本数据
    • 事件发生时间
    • 发生时页面信息快照
  • 页面
    • 页面 PV,UV
    • 用户页面停留时长
    • 页面跳转事件
    • 页面进入后台
    • 用户离开页面
  • 用户信息
    • 用户 uid
    • 用户设备指纹
    • 设备信息
    • ip
    • 定位
  • 用户操作行为
    • 用户点击
      • 点击目标
  • 页面 AJAX 请求
    • 请求成功
    • 请求失败
    • 请求超时
  • 页面报错
    • 资源加载报错
    • JS 运行报错
  • 资源加载新性能
  • 图片
  • 脚本
  • 页面加载性能

上面的数据通过 3 个维度来定义埋点事件

  • ·LEVEL: 描述埋点数据的日志级别
    • INFO:一些用户操作,请求成功,资源加载等等正常的数据记录
    • ERROR: JS报错,接口报错等等错误类型的数据记录
    • DEBUG: 预留开发人员通过手动调用的方式回传排除bug的数据记录
    • WARN: 预留开发人员通过手动调用的方式回传非正常用户行为的的数据记录
  • CATEGORY:描述埋点数据的分类
    • TRACK: 埋点SDK对象的生命周期管理整个埋点数据。
      • WILL_MOUNT:sdk对象即将初始化加载,生成一个默认ID,跟踪全部相关事件
      • DID_MOUNTED:sdk对象初始化完成,主要获取设备指纹等等的异步操作完成
    • AJAX: AJAX相关数据
    • ERROR:页面中的异常相关数据
    • PERFORMANCE: 关于性能相关数据
    • OPERATION: 用户操作相关数据
  • EVENT_NAME:具体的事件名称

根据上述的维度,我们可以简单设计如下的架构

初探埋点系统

根据上图的架构,再进行下面的具体代码开发

代理请求

在浏览器中现在主要有 2 种请求方式,一个是 XMLHttpRequest, 一个是 Fetch

代理 XMLHttpRequest

function NewXHR() {  var realXHR: any = new OldXHR(); // 代理模式里面有提到过
  realXHR.id = guid()  const oldSend = realXHR.send;

  realXHR.send = function (body) {
    oldSend.call(this, body)    //记录埋点
  }
  realXHR.addEventListener('load', function () {    //记录埋点
  }, false);
  realXHR.addEventListener('abort', function () {    //记录埋点
  }, false);

  realXHR.addEventListener('error', function () {    //记录埋点
  }, false);
  realXHR.addEventListener('timeout', function () {    //记录埋点
  }, false);  return realXHR;
}复制代码
登录后复制

代理 Fetch

 const oldFetch = window.fetch;  function newFetch(url, init) {    const fetchObj = {      url: url,      method: method,      body: body,
    }
    ajaxEventTrigger.call(fetchObj, AJAX_START);    return oldFetch.apply(this, arguments).then(function (response) {      if (response.ok) {       //记录埋点
      } else {       //上报错误
      }      return response
    }).catch(function (error) {
      fetchObj.error = error        //记录埋点      
        throw error
    })
  }复制代码
登录后复制

监听页面的 PVUV

在进入页面时,我们通过算法生成一个唯一 session id,作为这次埋点行为的全局 id,上报用户 id,设备指纹,设备信息。在用户未登录的情况下,通过设备指纹来计算 UV,通过 session id计算 PV

异常捕获

异常就是干扰程序的正常流程的不寻常事故

RUNTIME ERROR

JS中可以通过 window.onerrorwindow.addEventListener('error', callback) 捕捉运行时异常,一般使用window.onerror,它兼容性更好。

window.onerror = function(message, url, lineno, columnNo, error) {    const lowCashMessage = message.toLowerCase()    if(lowCashMessage.indexOf('script error') > -1) {      return
    }    const detail = {      url: url    
      filename: filename,      columnNo: columnNo,      lineno: lineno,      stack: error.stack,      message: message
    }    //记录埋点}复制代码
登录后复制

Script Error

在这里我们过滤了 Script Error, 它产生的原因主要是页面中加载的第三方跨域脚本报错,比如托管在第三方 CDN 中的 js 脚本。这类问题比较难以排查。解决的方法有:

  • 打开 CORS(Cross Origin Resource Sharing,跨域资源共享),如下步骤
    • <srcipt src="another domain/main.js" cossorigin="anonymous"></script>
    • 修改Access-Control-Allow-Origin: * | 指定域名
  • 使用 try catch
      <script scr="crgt.js"></script> //加载crgt脚本,window.crgt = {getUser: () => string}
      try{      window.crgt.getUser();
      }catch(error) {      throw error // 输出正确的错误堆栈
      }复制代码
    登录后复制

Promise reject

js 在异步异常时无法通过 onerror 方法捕获 ,在 Promise 对象在 reject 时,同时并没有进行处理时 会抛出一个 unhandledrejection 的错误,并不会被上述的方法所捕获,所以需要添加单独的处理事件。

window.addEventListener("unhandledrejection", event => {  throw event.reason
});复制代码
登录后复制

资源加载异常

在浏览器中,可以通过 window.addEventListener(&#39;error&#39;, callback) 的方式监听资源加载异常,比如 js 或者 css 脚本文件丢失。

window.addEventListener(&#39;error&#39;, (event) => {  if (event.target instanceof HTMLElement) {    const target = parseDom(event.target, [&#39;src&#39;]);    const detail = {      target: target,      path: parseXPath(target),
    }    //  记录埋点
  }
}, true)复制代码
登录后复制

监听用户行为

通过 addEventListener click 监听 click 事件

window.addEventListener(&#39;click&#39;, (event) => {    //记录埋点}, true)复制代码
登录后复制

在这里通过组件的 displaName 来定位元素的位置,displaName 表示组件的文件目录,比如 src/components/Form.js 文件导出的组件 FormItem 通过 babel plugin 自动添加属性 @components/Form.FormItem,或者使用者主动给组件添加 static 属性 displayName

页面路由变化

  • hashRouter 监听页面hash变化,对hash进行解析
window.addEventListener(&#39;hashchange&#39;, event => {  const { oldURL, newURL } = event;  const oldURLObj = url.parseUrl(oldURL);  const newURLObj = url.parseUrl(newURL);  const from = oldURLObj.hash && url.parseHash(oldURLObj.hash);  const to = newURLObj.hash && url.parseHash(newURLObj.hash);  if(!from && !to ) return;  // 记录埋点})复制代码
登录后复制

监听页面离开

通过 addEventListener beforeunload 监听离开页面事件

window.addEventListener(&#39;beforeunload&#39;, (event) => {    //记录埋点})复制代码
登录后复制

SDK 架构

class Observable {    constructor(observer) {
        observer(this.emit)
    }
    emit = (data) => {        this.listeners.forEach(listener => {
            listener(data)
        })
    }
    listeners = [];
    
    subscribe = (listener) => {        this.listeners.push(listeners);        return () => {            const index = this.listeners.indexOf(listener);            if(index === -1) {                return false
            }            
            this.listeners.splice(index, 1);            return true;
        }
     }
}复制代码
登录后复制
const clickObservable = new Observable((emit) => {    window.addEventListener(&#39;click&#39;, emit)
})复制代码
登录后复制

然而在处理 ajax,需要将多种数据组合在一起,需要进行 merg 操作,则显得没有那么优雅,也很难适应后续复杂的数据流的操作。

const ajaxErrorObservable = new Observable((emit) => {    window.addEventListener(AJAX_ERROR, emit)
})const ajaxSuccessObservable = new Observable((emit) => {    window.addEventListener(AJAX_SUCCESS, emit)
})const ajaxTimeoutObservable = new Observable((emit) => {    window.addEventListener(AJAX_TIMEOUT, emit)
})复制代码
登录后复制

可以选择 RxJS 来优化代码

export const ajaxError$ = fromEvent(window, &#39;AJAX_ERROR&#39;, true)export const ajaxSuccess$ = fromEvent(window, &#39;AJAX_SUCCESS&#39;, true)export const ajaxTimeout$ = fromEvent(window, &#39;AJAX_TIMEOUT&#39;, true)复制代码
登录后复制
ajaxError$.pipe(
    merge(ajaxSuccess$, ajaxTimeout$), 
    map(data=> (data) => ({category: &#39;ajax&#39;, data; data}))
    subscribe(data => console.log(data))复制代码
登录后复制

通过 merge, map 两个操作符完成对数据的合并和处理。

数据流

初探埋点系统

项目结构

  • core
    • event$ 数据流合并
    • snapshot 获取当前设备快照,例如urluserIDrouter
    • track 埋点类,组合数据流和日志。
  • logger
    • logger 日志类
      • info
      • warn
      • debug
      • error
  • observable
    • ajax
    • beforeUpload
    • opeartion
    • routerChange
    • logger
    • track

参考

  • www.alibabacloud.com/help/zh/doc…

结尾

自建埋点系统是一个需要前后端一起合作的事情,如果人力不足的情况下,建议使用第三方分析插件,例如 Sentry 就能足够满足大部分日常使用

但还是建议多了解,在第三方插件出现不能满足业务需求的时候,可以顶上。

想了解更多编程学习,敬请关注php培训栏目!

以上是初探埋点系统的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

JavaScript和WebSocket:打造高效的实时图像处理系统 JavaScript和WebSocket:打造高效的实时图像处理系统 Dec 17, 2023 am 08:41 AM

JavaScript是一种广泛应用于Web开发的编程语言,而WebSocket则是一种用于实时通信的网络协议。结合二者的强大功能,我们可以打造一个高效的实时图像处理系统。本文将介绍如何利用JavaScript和WebSocket来实现这个系统,并提供具体的代码示例。首先,我们需要明确实时图像处理系统的需求和目标。假设我们有一个摄像头设备,可以采集实时的图像数

See all articles