事情的原委
领导:我们的项目发展到一定阶段了,想看下项目的使用情况,用户访问了哪些页面,点了哪些按钮 我:好的,我去预研一下技术方案 领导:我看友盟不错,你预研一下 我:好的,友盟可能需要收费 领导:……,我们工期也比较紧 我:好的,我先写一个满足需求的,先跑起来再说
我要做什么
项目的使用情况
从不同的视图会得到不同的需求
- 从产品视角看,在意的是pv、uv、转化率、页面留存等。一般叫做埋点
- 从研发视角看,在意的是性能(首屏时间、资源加载耗时)、错误(JavaScript错误、资源加载1异常)、用户体验(白屏、卡顿等)。一般叫做监控
埋点、监控傻傻分不清楚
其实很多产品、研发对于埋点和监控都没有很清晰的边界。像我的产品就会把埋点和监控的功能都混在一份excel里面发给我,我和我的主管、同时讨论的时候,也会出现两个内容混做一谈的情况。
那么这两个到底怎么区分呢?
埋点
埋点主要是数据上报,将用户对项目交互情况上报到收集平台,做数据统计,数据分析,为产品如何更好的规划项目提供数据方面的支持,也为业务的实现情况提供数据的支撑。
埋点的本质是数据上报,所以一定不会离开一些维度的数据:地理位置、页面路径、浏览器信息、用户标识、时间戳等等。还会有一些业务相关的:比如点击了哪些页面,访问了哪些内容,业务之间的转化率等等,就会附带一些业务的标识。
监控
监控主要是从技术的角度分析项目,比如项目有没有出错,出了哪些错误,性能怎么样,用户要等多久等等方面为项目提供数据的支持。所以也就细分为JS错误监控,接口错误监控,页面性能监控,资源加载监控……巴拉巴拉的。
监控实现的原理是什么? 无非就是几个API
- JS错误:windwo.onerror
- 接口异常:axios的响应拦截器,fetch、xhr包一层函数
- 页面性能:PerformanceAPI
- 资源加载错误:script标签,img标签都支持
我要怎么做
当我们理清楚了什么是什么之后,就会诞生新的问题:然后嘞?
埋点
站在产品的角度拆分问题:发生了什么事情(上报什么事件)
- 用户什么时候登陆的
- 用户什么时候登出的
- 用户访问了哪些地址
- 用户访问了哪些业务逻辑
监控
站在研发大佬的角度分析问题:性能怎么样(没出啥大问题吧)
- 首屏响应的时间
- 项目出了哪些错误
- 页面的加载资源情况怎么样
如何去做呢(这里会干一些)
埋点
所谓数据监控就是能拿到用户的行为,我们也需要注意那么几点:
- PV访问来量(Page View)
- UV访问数(Unique Visitor)
- 记录操作系统和浏览器
- 记录用户在页面的停留时间
- 进入当前页面的来源网页(也就是从哪进来的转化)
页面的基本信息
页面的性能信息
我咋拿嘞?
// 通过 performanceAPI 获取参数
let timing = performance.timing,
start = timing.navigationStart,
dnsTime = 0,
tcpTime = 0,
firstPaintTime = 0,
domRenderTime = 0,
loadTime = 0;
// 根据提供的api和属性,拿到对应的时间
dnsTime = timing.domainLookupEnd - timing.domainLookupStart;
tcpTime = timing.connectEnd - timing.connectStart;
firstPaintTime = timing.responseStart - start;
domRenderTime = timing.domContentLoadedEventEnd - start;
loadTime = timing.loadEventEnd - start;
console.log('DNS解析时间:', dnsTime,
'\nTCP建立时间:', tcpTime,
'\n首屏时间:', firstPaintTime,
'\ndom渲染完成时间:', domRenderTime,
'\n页面onload时间:', loadTime);
// 页面加载时发送埋点请求
$(document).ready(function(){
// ... 这里存在一些业务逻辑
sendRequest(params);
});
// 按钮点击时发送埋点请求
$('button').click(function(){
// 这里存在一些业务逻辑
sendRequest(params);
});
// 通过伪装成 Image 对象,传递给后端,防止跨域
let img = new Image();
let src = `http://xxx/a.jpg?args=${encodeURIComponent(args)}`;
img.src = src;
//css实现的埋点
.link:active::after{
content: url("http://www.example.com?action=yourdata");
}
<a class="link">点击我,会发埋点数据</a>
//data自定义属性,rangjs去拿到属性绑定事件,实现埋点
//<button data-mydata="{key:'uber_comt_share_ck', act: 'click',msg:{}}">打车</button>