前端埋点数据收集和数据上报

原文地址

什么是埋点

学名叫时间追踪(Event Tracking), 主要针对用户行为或者业务过程进行捕获,处理和发送相关技术及实施过程.
埋点是数据领域的一个专业术语,也是互联网领域的俗称,是互联网领域的俗称

埋点是产品数据分析的基础,一般用于推荐系统的反馈、用户行为的监控和分析、新功能或者运营活动效果的统计分析等。

埋点包含两个重要概念:事件(event),属性(param)

  • 事件(event):应用中发生了什么,例如用户操作、系统事件或系统错误。以你拍一产品为例,包含以下事件:enter_page(进入页面)、leave_page(离开页面)。
  • 属性(param):为了描述用户群细分而定义的属性,例如语言偏好或地理位置。以“进入课后练习”事件为例,它包含如下事件属性:enter_from(从哪个页面来),class_id(课程id)等。
  • 属性值(value):属性的维度,即行为触发时的具体维度。例如:enter_from:home(主页)、system(系统)等。

主流方案

无痕埋点(全埋点),利用浏览器或APP自带的监听方式,对用户的浏览页面、点击等行为进行手机,一般用于粗颗粒度的数据分析,例如公司的slardar
缺点:

  • 数据噪声大,不管有用没有,数据都会被收集
  • 无法定制化埋点,无法采集到指定事件和业务属性
  • 可供DA使用的信息较少
    优点:
  • 接入简单,几乎无侵入,不需要额外的开发成本
  • 用户操作行为收集非常完整,几乎不会遗漏

代码埋点, 前端开发人员在代码中自定义监听和收集
缺点:

  • 工作量大,而且对代码侵入性大,后期维护不方便
    优点:
  • 可以精确埋点,具备明确的事件标识
  • 业务员属性非常丰富
  • 埋点触发方式可以灵活定义
  • DA使用更方便和精确

埋点SDK,SDK向外暴露上报埋点的接口,监听和收集过程开发人员无感知,例如公司的tea
缺点:NA
优点:

  • 业务开发只需要关注事件标识,业务属性等
  • 兼顾无痕埋点优点和代码埋点的优势

常见的埋点属性

通常前端是按照页面维度统计埋点的,常见的事件属性如下

属性描述
uid用户id,如果用户未登录,则返回特定标识id
url当前事件触发页面的url
eventTime触发埋点的时间戳
localTime触发埋点的用户本地时间,使用标准YYYY=MM-DD HH:mm:ss格式表示,方便后期直接使用字符串查询
device Type当前用户使用的设备类型,比如apple、三星、chrome
deviceId当前用户使用的设备id
osType系统类型入windows,macos,ios,android
osVersion系统版本
appVersion应用版本
appId当前应用id
extra自定义数据,一般是序列化的字符串,且数据结构应该保持稳定

常见埋点事件

事件上报时机描述
页面停留当前页面切换或者页面卸载时记录前一页浏览时间
pv进入页面时页面访问次数,uv只需要根据deviceId过滤
交互事件用户交互事件触发时比如点击、长按等
逻辑事件符合逻辑条件时比如登录、跳转页面等

性能数据采集方案

目前性能指标数据大部分来源于 window.performance API。

在这里插入图片描述
在这里插入图片描述

参数名描述
connectEndHTTP(TCP) 返回浏览器与服务器之间的连接建立时的时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。
connectStartHTTP(TCP) 域名查询结束的时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 fetchStart一致。
domComplete当前文档解析完成,即Document.readyState 变为 'complete’且相对应的readystatechange 被触发时的时间戳
domContentLoadedEventEnd当所有需要立即执行的脚本已经被执行(不论执行顺序)时的时间戳。
domContentLoadedEventStart当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的时间戳。
domInteractive当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳。
domLoading当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的时间戳。
domainLookupEndDNS 域名查询完成的时间。如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
domainLookupStartDNS 域名查询开始的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和fetchStart一致。
fetchStart浏览器准备好使用HTTP请求来获取(fetch)文档的时间戳。这个时间点会在检查任何应用缓存之前。
loadEventEnd当load事件结束,即加载事件完成时的时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0.
loadEventStartload事件被发送时的时间戳。如果这个事件还未被发送,它的值将会是0。
navigationStart同一个浏览器上一个页面卸载(unload)结束时的时间戳。如果没有上一个页面,这个值会和fetchStart相同。
redirectEnd最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0.
redirectStart第一个HTTP重定向开始时的时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0。
requestStart返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳。
responseEnd返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的时间戳。
responseStart返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳。如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间
secureConnectionStartHTTPS 返回浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,则返回0。
unloadEventEnd和 unloadEventStart 相对应,unload事件处理完成时的时间戳。如果没有上一个页面,这个值会返回0。
unloadEventStart上一个页面unload事件抛出时的时间戳。如果没有上一个页面,这个值会返回0。

常见性能指标

指标名字描述
FP页面首次绘制时间
FCP页面首次有内容绘制的时间
FMP页面首次有效绘制时间 FMP>=FCP
TTI页面完全可交互时间
FID页面加载阶段,用户首次交互操作的延时时间
MPFID页面加载阶段,用户交互操作可能遇到的最大延时时间
LOAD页面完全加载的时间(load事件发生的时间)

FP

FP(FIrst Paint) 指标通常会反映页面的白屏时间,白屏时间会反应当前,用户等待内容时间就会越短,Web页面的网络加载性能情况,当加载性能非常良好的情况下,白屏时间就会越短,用户流失概率越低

该指标可以通过 preformance.getEntriesByType(‘paint’) 方法获取 PerformancePaintTming API 提供的打点信息,找到name为first-paint的 对象,描述的即为FP的指标数据:
在这里插入图片描述

FCP

FCP(First Contentful Paint) 为首次有内容渲染的时间点,在性能统计指标中,从用户开始访问Web页面的时间点到FCP的时间,可以视为无内容时间,一般FCP >= FP

指标可以通过 performance.getEntriesByType(‘paint’) 方法获取PerformancePaintTiming API 提供的打点信息,找到 name 为 first-contentful-paint 的对象,描述的即为 FCP 的指标数据,如下图所示:

FMP

FMP(First Meaningful Paint), 即首次绘制有意义内容的时间,当整体页面的布局和文字内容全部渲染完成后,即可认为是完成了首次有意义内容的绘制。所以FMP衡量了用户看到网页的主要内容的时间,是用户体验角度的一种重要衡量指标

前端业界现在比较认可的一个计算 FMP 的方式就是「页面在加载和渲染过程中最大布局变动之后的那个绘制时间 」。可通过 MutationObserver 监听每一次页面整体的 DOM 变化,触发 MutationObserver 的回调,在回调计算出当前 DOM 树的变动分数,分数变化最剧烈的时刻,即为 FMP 的时间点。

TTI

TTI(Time To Interactive),即从页面加载开始到页面处于完全可交互状态所花费的时间。页面处于完全可交互状态时,满足以下 3 个条件:

页面已经显示有用内容。
页面上的可见元素关联的事件响应函数已经完成注册。
事件响应函数可以在事件发生后的 50ms 内开始执行。

资源加载指标

window.performance.getEntriesByType(‘resource’)会返回当前页面加载的所有资源(js、css、img…)的各类性能指标,可用于静态资源性能数据采集。

主要类型有:script、link、img、css、xmlhttprequest、beacon、fetch、other。
PerformanceResourceTiming - Web APIs | MDN

其他指标计算方式

指标名描述计算方式
DNS查询DNS 阶段耗时domainLookupEnd - domainLookupStart
TCP连接TCP 阶段耗时connectEnd - connectStart
SSL建连SSL 连接时间connectEnd - secureConnectionStart
首字节网络请求首字节响应时间(ttfb)responseStart - requestStart

错误数据采集方案

有三种

  • 资源加载错误,通过 addEventListener(‘error’, callback, true) 在捕获阶段捕捉资源加载失败错误。
  • js 执行错误,通过 window.onerror 捕捉 js 错误。
    • 跨域的脚本会给出 “Script Error.” 提示,拿不到具体的错误信息和堆栈信息。此时需要在script标签增加crossorigin="anonymous"属性,同时资源服务器需要增加CORS相关配置,比如Access-Control-Allow-Origin: *
  • promise 错误,通过 addEventListener(‘unhandledrejection’, callback)捕捉 promise 错误,但是没有发生错误的行数,列数等信息,只能手动抛出相关错误信息。
// 在捕获阶段,捕获资源加载失败错误
Element.addEventListener('error', e => {
const target = e.target
    if (target != window) {
        monitor.errors.push({
            type: target.localName,
            url: target.src || target.href,
            msg: (target.src || target.href) + ' is load error',
            time: Date.now()
        })
    }
})

// 监听 js 错误
window.onerror = function(msg, url, row, col, error) {
    monitor.errors.push({
        type: 'javascript',
        row: row,
        col: col,
        msg: error && error.stack? error.stack : msg,
        url: url,
        time: Date.now()
    })
}
// 监听 promise 错误 缺点是获取不到行数数据
addEventListener('unhandledrejection', e => {
    monitor.errors.push({
        type: 'promise',
        msg: (e.reason && e.reason.msg) || e.reason || '',
        time: Date.now()
    })
})

数据上报方案

在这个场景中,需要考虑两个问题:

如果数据上报接口与业务系统使用同一域名,浏览器对请求并发量有限制,所以存在网络资源竞争的可能性。
浏览器通常在页面卸载时会忽略异步ajax请求,如果需要必须进行数据请求,一般在unload或者beforeunload事件中创建同步ajax请求,以此延迟页面卸载。从用户侧角度,就是页面跳转变慢。

Beacon

在这里插入图片描述
除开ie浏览器,目前主流现代浏览器对beacon的支持率非常高。Beacon - MDN文档

Beacon 接口用来调度向 Web 服务器发送的异步非阻塞请求。

  • Beacon 请求使用 HTTP POST方法,并且不需要有响应。
  • Beacon 请求能确保在页面触发 unload 之前完成初始化。

通俗的讲就是,Beacon可将数据异步发送至服务端,且能够保证在页面卸载完成前发送请求(解决ajax页面卸载会终止请求的问题)。使用方法如下:

navigator.sendBeacon(url, data);

其中 data 参数是可选的,它的类型可以为 ArrayBufferView, Blob, DOMString 或者 FormData。如果浏览器成功地将 beacon 请求加入到待发送的队列里,这个方法将会返回 true ,否则将会返回 false

使用Beacon时需要后台需要使用post方法接收参数,考虑到跨域问题,后台还需要改造接口配置CORS。同时请求头必须满足CORS-safelisted request-header,其中content-type的类型必须为application/x-www-form-urlencoded, multipart/form-data, 或者text/plain。

type ContentType = 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain';

const serilizeParams = (params: object) => {
    return window.btoa(JSON.stringify(params))
}

function sendBeacon(url: string, params: object) {
  const formData = new FormData()
  formData.append('params', serilizeParams(params))
  navigator.sendBeacon(url, formData)
}

Image

sendBeacon的兼容性问题是不可避免的,不过可以充分利用大部分浏览器会在页面卸载前完成图片的加载的特性,通过在页面添加img的方式上报数据。

function sendImage(url: string, params: object) {
  const img = new Image()

  img.style.display = 'none'

  const removeImage = function() {
    img.parentNode.removeChild(img)
  }

  img.onload = removeImage
  img.onerror = removeImage

  img.src = `${url}?params=${serilizeParams(params)}`

  document.body.appendChild(img)
}

由于img图片为get请求方式,不同服务器针对uri的长度有限制,长度超过限制时会出现HTTP 414错误,所以还要注意上报频率,减少一次性上传的属性过多。

兼容方案

优先使用sendBeacon的方式,Image方式作为fallback。


function sendLog(url: string, params: object) {
    if(navigator.sendBeacon) {
        sendBeacon(url, params)
    } else {
        sendImage(url, params)
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/789454.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AIGC】一、本地docker启动私有大模型

本地docker启动私有大模型 一、最终效果中英文对话生成代码 二、资源配置三、搭建步骤启动docker容器登录页面首次登录请注册登录后的效果 配置模型尝试使用选择模型选项下载模型选择适合的模型开始下载 试用效果返回首页选择模型中英文对话生成代码 四、附录资源监控 五、参考…

动手学深度学习54 循环神经网络

动手学深度学习54 循环神经网络 1. 循环神经网络RNN2. QA 1. 循环神经网络RNN h t h_t ht​ 与 h t − 1 h_{t-1} ht−1​ x t − 1 x_{t-1} xt−1​有关 x t x_t xt​ 与 h t h_t ht​ x t − 1 x_{t-1} xt−1​ 有关 怎么把潜变量变成RNN–假设更简单 潜变量和隐变量的区…

Java面试八股之什么是布隆过滤器

什么是布隆过滤器 布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素是否可能存在于一个集合中。布隆过滤器可以给出“可能存在”或“一定不存在”的答案,但不能保证“一定存在”。其主要特点是&…

WTM的项目中EFCore如何适配人大金仓数据库

一、WTM是什么 WalkingTec.Mvvm框架(简称WTM)最早开发与2013年,基于Asp.net MVC3 和 最早的Entity Framework, 当初主要是为了解决公司内部开发效率低,代码风格不统一的问题。2017年9月,将代码移植到了.Net Core上&…

开源项目有哪些机遇与挑战

目录 1.概述 2.开源项目的发展趋势 2.1. 开源项目的发展现状 2.2. 开源社区的活跃度 2.3. 开源项目在技术创新中的作用 3.参与开源的经验分享 3.1. 选择开源项目 3.2. 理解项目结构和文档 3.3. 贡献代码 3.4. 与开源社区的合作 3.5. 学习和成长 4.开源项目的挑战 …

buuctf 二维码

文件下载下来是一个png的文件 做misc永远的好习惯就是先运行,后010 先运行,这个运行肯定就是扫码 啥也没有 里面还有个ZIP文件(zip的发明人名字是PK) 放在kali上binwalk分离 CTF工具隐写分离神器Binwalk安装和详细使用方法_binwalk下载-CSDN博客 里面有个text,需要密码 我…

ESP32驱动摄像头:1.驱动OV2640模块(待验证)

一、装ArduCam库和ESPAsyncWebServer库 二、参考代码 #include <Wire.h> #include <ArduCAM.h> #include <SPI.h> #include <WiFi.h> #include <ESPAsyncWebServer.h>#define CAM_CS 32 // modify according to your own wiring #define OV2640…

IP 地址:优化网络游戏

IP地址和网络游戏 在现代网络游戏中&#xff0c;IP地址不仅用于服务器分配&#xff0c;还能针对性进行玩家匹配与优化网络延迟。本文将探讨IP地址在网络游戏中的具体应用。 *服务器分配* 全球服务器分布&#xff1a; 网络游戏需要在全球范围内提供快速、稳定的连接&#xff…

【机器学习】主成分分析(PCA):数据降维的艺术

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 主成分分析&#xff08;PCA&#xff09;&#xff1a;数据降维的艺术引言PCA的基…

【TypeScript 学习】TypeScript 枚举类型发散:基于位运算的权限管理 CRUD 操作

文章目录 TypeScript 枚举类型发散&#xff1a;基于位运算的权限管理 CRUD 操作1 问题由来2 具体实现2.1 新增权限2.2 删除权限2.3 查询权限&#xff08;即判定存在与否&#xff09;2.4 修改权限2.5 完整测试 3 小结 TypeScript 枚举类型发散&#xff1a;基于位运算的权限管理 …

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【加解密(C/C++)】

加解密(C/C) 以AES 256密钥为例&#xff0c;完成加解密。具体的场景介绍及支持的算法规格。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生成密钥 指定密钥别名。初始化密钥属性集。调用OH_Huks_GenerateKeyItem生成密钥)…

[Linux安全运维] Linux用户以及权限管理

Linux用户以及权限管理 Linux用户和组 用户信息文件pasawd /etc/passwd文件用于存储用户的信息 :用于分割不同的字段信息 字段示例&#xff08;第一行&#xff09;含义说明1root用户名2x密码占位符x代表用户有密码存储在shadow文件中无内容代表用户登录系统不需要密码30UID…

一款24小时实时检测的六氟化硫气体泄漏报警系统

尽管当前工业生产模式越来越趋于自动化、智能化&#xff0c;但安全生产仍然是时下屡被提及的话题。在配电室等使用六氟化硫气体的众多领域中&#xff0c;由于气体泄漏而引发的中毒、火灾、爆炸、窒息事故仍高发频发。因此&#xff0c;安装六氟化硫气体泄漏报警监测系统仍是企业…

C语言 | Leetcode C语言题解之第226题翻转二叉树

题目&#xff1a; 题解&#xff1a; struct TreeNode* invertTree(struct TreeNode* root) {if (root NULL) {return NULL;}struct TreeNode* left invertTree(root->left);struct TreeNode* right invertTree(root->right);root->left right;root->right le…

如何探索高效知识管理:FlowUs知识库体验很好

在当今信息爆炸的时代&#xff0c;有效的知识管理对于个人和团队的发展至关重要。FlowUs 知识库作为一款创新的知识管理工具&#xff0c;正逐渐成为众多用户的首选&#xff0c;为他们带来了高效、便捷和有条理的知识管理体验。 FlowUs 知识库的一大特色在于其简洁直观的界面设计…

基于单片机的温控光控智能窗帘设计探讨

摘 要&#xff1a; 文章使用的核心原件是 AT89C52 单片机&#xff0c;以此为基础进行模块化的设计&#xff0c;在整个设计中通过加入光检测模块和温度检测模块&#xff0c;从而对室内的温度和光照强度进行检测&#xff0c;然后将检测得到的数据传输给单片机&#xff0c;单片机…

【自用】【高昆轮概率论与数理统计笔记】2.1 分布函数的概念与性质

不定期更新&#xff0c;前面的章节会在学完后补回来&#xff0c;重新学学概率&#xff0c;当年考研考的数学二&#xff0c;没有概率基础&#xff0c;想自己补补&#xff0c;视频课是高昆轮老师讲的浙大四版概率论教材的视频课&#xff0c;地址&#xff1a; 第一章&#xff1a;h…

印尼“支付宝” DANA 如何借力 OceanBase 实现3个“关键零”

当前&#xff0c;移动支付在东南亚正迅猛发展&#xff0c;据谷歌、淡马锡与贝恩公司发布的报告预测&#xff0c;东盟地区蓬勃兴起的移动支付市场有望在2030年突破至2万亿美元的交易规模。 在此背景下&#xff0c;DANA作为印尼——东南亚最大经济体中的一员&#xff0c;秉持着推…

基于vue的引入登录界面

以下是一些常见的登录页面布局&#xff1a; 1. 中心布局 - 登录表单位于页面的中心位置&#xff0c;通常包括用户名输入框、密码输入框、登录按钮等元素。页面背景简洁&#xff0c;以突出登录表单。 - 这种布局常见于大多数网站和应用&#xff0c;简洁明了&#xff0c;用户注意…

Android 性能优化之内存优化

文章目录 Android 性能优化之内存优化内存问题内存抖动内存泄露内存溢出 检测工具Memory ProfilerMemory AnalyzerLeakCanary 内存管理机制JavaAndroid 解决内存抖动问题模拟问题代码使用Memory Profiler工具检测优化技巧 内存泄露问题模拟问题代码使用LeakCanary工具检测优化技…