zhaobinglong / myBlog

https://zhaobinglong.github.io/myBlog/
MIT License
7 stars 0 forks source link

前端无痕埋点系统的设计和实现 #111

Open zhaobinglong opened 3 years ago

zhaobinglong commented 3 years ago

参考

正确的pv统计 https://zhuanlan.zhihu.com/p/26341409 PC端统计脚本 https://juejin.im/post/6891080391642316808 https://juejin.im/post/5dba5a39e51d452a2378348a

系统目标

系统阶段分析

信息收集四个维度

a. 用户信息 出现异常时该用户的信息,例如该用户在当前时刻的状态、权限等,以及需要区分用户可多终端登录时,异常对应的是哪一个终端。

b. 行为信息 用户进行什么操作时产生了异常:所在的界面路径;执行了什么操作;操作时使用了哪些数据;当时的API吐了什么数据给客户端;如果是提交操作,提交了什么数据;上一个路径;上一个行为日志记录ID等。

c. 异常信息 产生异常的代码信息:用户操作的DOM元素节点;异常级别;异常类型;异常描述;代码stack信息等。

d. 环境信息 网络环境;设备型号和标识码;操作系统版本;客户端版本;API接口版本等。

两种捕获类型

前端捕获异常分为全局捕获和单点捕获。全局捕获代码集中,易于管理;单点捕获作为补充,对某些特殊情况进行捕获,但分散,不利于管理。

a、全局捕获 通过全局的接口,将捕获代码集中写在一个地方,可以利用的接口有:window.addEventListener(‘error’) / window.addEventListener(“unhandledrejection”) / document.addEventListener(‘click’) 等框架级别的全局监听,例如aixos中使用interceptor进行拦截,vue、react都有自己的错误采集接口

b、单点捕获 在业务代码中对单个代码块进行包裹,或在逻辑流程中打点,实现有针对性的异常捕获:try…catch专门写一个函数来收集异常信息,在异常发生时,调用该函数

埋点分类

市面产品

开源js错误监控解决方案

badjs Webfunny zanePerfor

开源SDK学习

小程序日志上报SDK https://github.com/wangweianger/web-report-sdk/blob/master/src/web-report-axios.js 智云大健康开源前端SDK:https://juejin.cn/post/6862559324632252430

zhaobinglong commented 3 years ago

数据上报策略

// 每10条数据数据进行打包, 批量上报方案实现
let logs = []
/**
 * @params {array} 日志数组
 */
function upload (logs) {
  console.log('send logs', logs)
  let xhr = new XMLHttpRequest()
  let data = new FormData()
  data.append('logs', logs)
  xhr.open('POST', this.url)
  xhr.send(data)
}

export default function analytics (action = 'pageview', params) {
  logs.push(Object.assign({
    action,
    timeStamp: Date.now()
  }, params))
  if (logs.length >= 10) {
    upload(logs)
    logs = []
  }
}

延迟上报丢失数据问题

延迟上报策略下,如果没有达到数据上报的条件,用户退出页面,在用户不再进入的情况下,本地数据无法上报 解决方案:监听页面生命周期中的beforeunload事件,在页面离开前把剩余不足N条的log全部上传

// sendBeacon允许脚本在页面卸载后异步上web服务器发送少量数据
window.addEventListener('unload', logData, false);
function logData() {
    navigator.sendBeacon("/log", analyticsData);
}

单页面模式下的pv上报

// 监听hash的切换,一旦hash发生变化,就认为是一个新的PV
window.addEventListener('hashchange', () => {
  this.analytics()
})

无网络延时上报/失败后重传策略

我们可以尝试增加“失败重传”的功能,比起网络不稳定,更多的情况是某个问题导致的稳定错误,重传不能解决这类问题。设想我们在客户端进行数据收集,我们可以很方便地记录到log文件中,于是同样的考虑,我们也可以把数据暂存到localstorage上面,有网环境下再继续上报,因此解决这个问题的方案我们可以归纳为:

上报数据量太大处理

一次性上传批量数据时,必然遇到数据量大,浪费流量,或者传输慢等情况,网络不好的状态下,可能导致上报失败。因此,在上报之前进行数据压缩也是一种方案。

对于合并上报这种情况,一次的数据量可能要十几k,对于日 pv 大的站点来说,产生的流量还是很可观的。所以有必要对数据进行压缩上报。lz-string是一个非常优秀的字符串压缩类库,兼容性好,代码量少,压缩比高,压缩时间短,压缩率达到惊人的60%。但它基于LZ78压缩,如果后端不支持解压,可选择gzip压缩,一般而言后端会默认预装gzip,因此,选择gzip压缩数据也可以,工具包pako中自带了gzip压缩,可以尝试使用。

参考

https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/sendBeacon

zhaobinglong commented 3 years ago

捕获代码错误

捕获资源加载失败错误

捕获异步回调错误

zhaobinglong commented 3 years ago

服务器端设计

zhaobinglong commented 3 years ago

上报方式之Head请求

考虑到上报数据过程我们并不关心返回值,只需要知道上报成功与否,我们可以用Head请求来更高效地实现我们的上报过程。

上报方式之image beacon(完美跨域)

// 简洁的方式
export default function analytics (action = 'pageview') {
  (new Image()).src = `https://xxx/test_upload?action=${action}&timestamp=${Date.now()}`
}

参考

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/HEAD

zhaobinglong commented 3 years ago

链式操作埋点思路

zhaobinglong commented 3 years ago

微信小程序无痕埋点技术方案

写Page函数。

参考

https://blog.csdn.net/milugloomy/article/details/100545190