前端监控主要为了获取用户行为以及跟踪产品端的使用情况,通过筛选合理数据,以大数据为依托,规划合理的产品优化方向
前端监控:主要分为三类:数据监控(埋点)、性能监控、异常监控
数据监控(埋点)
埋点常见收集点:
1. PV:页面浏览量;UV:浏览页面的自然人个数
2. 按钮点击/入口渠道/用户信息/访问的卡片信息/出发区域的空间信息
3. 页面停留时长
埋点方案
1.代码埋点
大家工作中经常使用的方案是代码埋点,开发人员按照埋点sdk,手动区分场景进行代码嵌入
前端埋点一般区分为:站外与自主app内
需要进行两端埋点的统一输入口径的封装
// 前端页面存在多渠道公用,简单的代理封装,让业务看起来更明了
let sendTracker = (options){
if(isMyApp){
APPSDK.SendTracker(options)
}else{
// sdk 发送
SendTracker(options)
}
}
上面说的接入入口发送,具体的业务接入才是最痛苦的,因为代码埋点直接侵袭了业务代码范畴,很难做到一个明确的隔离。对于业务数据分析师的考验也很大,如果数据联系分析不下功夫,那就变成前端要进行 “傻瓜式” 埋点收集
tips: 比方说:商品卡片交互事件统计,如浏览者为平台会员,展示的促销卡片样式。也就是卡片存在多种自定义的样式。
样式的依赖数据也就是用户身份
前端只需要上报 {productid: 'xxxxx',token: 'xxxxxxxxxxxxx'}
通过用户身份的获取,即可分析卡片的曝光率/点击率
? ? 当然前端上报全数据,对于分析师会节省很多计算操作,但全数据对于业务的侵入伤害会增加很多。很多业务模块不需要,不关注的字段,因为需要上报埋点数据,需要进行数据集中管理,这也就是前端会排斥很多埋点的最主要因素。
总结一句话:本来不需要,做完了也不需要,你来了,我必须要。可我真的不想要
常规的代码埋点方案在开发维护中,存在版本不同步,产品 & ui & 数据 & 技术 在交互流程简单调整的时候,可能并不会去过多在意是否会影响埋点流程代码。而埋点数据逻辑流程异常,数据上报是无状态的,并不具有很强的敏锐度。可能要很长时间才能会被感知
所有我们需要去把我一个度,就是尽量减少 埋点逻辑与业务逻辑的融合
移动端主要收集埋点交互的方式,大致分为两类: “曝光” 跟 “点击”
曝光:一般需要携带的发送的数据,不存在交互逻辑,基本为服务端直出,然后拼接页面公共数据进行上报
点击:强耦合业务逻辑
问题来了,如何减少呢
拿vue组件为例,业务组件模块分为:
style: 样式表
templete: html 模版
script: 组件自身逻辑处理/用户交互
埋点侵入最深的 script,业务组件后期变更最频繁的也便是js逻辑,这就变成了,日志 === 业务
如果业务开发中把大部分的埋点数据直接挂载到templete上, 逻辑 script 模块可有效减少代码。
提升一定的阅读维护效率
以前写的一套脱离框架的埋点上报方案
思想:所有需要埋点上报的数据,全部挂载到dom标签上,在特定交互时机进行页面扫描,check触发条件,上报
- 生命js库全局配置参数 支持扩展
let sendTracker = {
version: '1.0.0', // 版本
poll: null, // 扫描 time callback
throttle: 0, // 节流时长
showTime: 0, // 有效曝光时间
openSendShow:false, // 是否开启监测页面show
// offsetX dom 进入适口的偏移量
// offsetY dom 进入适口的偏移量
};
2.定义全局 “默认”数据 支持扩展
let globalData = {
'ua': navigator.userAgent,
'cookie': (() => {
let key = Cookies.get('MP_MD_UUID') // setcookie 设置唯一uid
if (!key) {
Cookies.set('MP_MD_UUID', UUID, {
expires: 365
})
}
return key
})(),
'source':(() => {
return getAppType(); //获取渠道
})(),
}
- check 元素是否正确显示在视口中
let inView = (ele) => {
//1. dom 元素是否显示中
// String.prototype.toLocaleLowerCase.apply(ele.style.display) !== 'none'
//2. to-do 判断元素是否在视口中
};
- 扫描所有dom元素节点,check 是否需要发送埋点,正确发送后,dom节点打上标记
/**
* 捕获所有节点
*/
let render = () => {
// 获取有效 show dom
let nodes = (function() {
let allNodes = document.getElementsByTagName("*");
allNodes = Array.prototype.slice.call(allNodes);
let mpNodes = [];
allNodes.forEach(dom => {
if(dom.getAttribute('mp_module_event') && dom.getAttribute('mp_module_event').indexOf('show') > -1){
// 发送埋点
mpNodes.push(dom)
}
});
return mpNodes;
})();
/**
* 循环遍历有效dom 节点 是否显示在视口
* dom 在适口中曝光的时间
*/
for (let i = 0; i < nodes.length; i++) {
let elem = nodes[i];
if (isShow(elem) && inView(elem)) {
if (!elem) {
return false;
}
setTimeout(function(){
if (isShow(elem) && inView(elem) && !elem.getAttribute('mp_send_status')) {
// 已显示 记录
elem.setAttribute('mp_send_status',true);
// console.log('已发送',elem)
sendTracker.sendTrackerMsg({},elem)
}else{
// console.log('时间不够',elem)
}
},sendTracker.showTime)
}else{
// console.log('未显示入口 || 隐藏元素',elem)
}
}
};
5.初始化埋点,合并配置项。同时注册监听
sendTracker.init = (config) => {
// 首先合并配置项
sendTracker.throttle = optionToInt(config.throttle, 200) //节流 200 毫秒
sendTracker.showTime = optionToInt(config.showtime, 150) // 曝光时间
// 更新全局发送数据
globalData = { ...globalData, ...config.global}
document.documentElement.addEventListener('touchstart',function(e){
let domlist = e.path;
for (let i = 0; i < domlist.length; i++) {
if(domlist[i]['nodeName'] == 'HTML'){break;}
if(domlist[i].getAttribute('iavn_module_event') && domlist[i].getAttribute('ivan_module_event').indexOf('click') > -1){
// 发送点击埋点
sendTracker.sendTrackerMsg({},domlist[i])
break;
}
}
},false)
// 是否开启 页面show的捕获
if(!sendTracker.openSendShow){return}
render();
// 注册页面全局交互监听
if (document.addEventListener) {
window.addEventListener('scroll', function(){
sendTracker.raf(render);
}, false);
window.addEventListener('touchstart', function(){
sendTracker.raf(render);
}, false);
window.addEventListener('load', function(){
sendTracker.raf(render);
}, false);
}
};
6.触发上报,收集特定规则属性(例如 ivan-productid)
sendTracker.sendTrackerMsg = (elem) => {
// to-do
// 获取dom 节点上 挂载特定表示 例如 ivan-xx-xx 属性数值 obj
// 上报发送
}
-
扩展类 api
1.切换发送地址 sendTracker.changeSendUrl // 变更数据上报地址 2.手动检测api sendTracker.handlecheck // 触发收集 3.销毁监听 sendTracker.detach 4.xxxxxx
将一些不牵扯复杂业务逻辑的埋点,挂载到 dom标签上面,需要定义的一些上报数据直接进行dom标签属性的挂载。在后续的开发过程中,逻辑业务js中需要处理的埋点,基本上很少,代码量也会得到大幅度减少,后续维护对于模块的阅读效率也会得到很大提升
数据安全的时代,完全可以强跟随业务模块,进行去统计数据的展示系统,可实现全司数据共享,实时数据可视化
2.无埋点
无埋点并不是说不需要埋点,而是全部埋点
前端的任意一个事件都被绑定一个标识,收录页面发生的一切。
上报统计数据,需要专业人员进行分析。
大家看到上面的解释,基本理解这个方案 高大上,有使用门槛,数据分析需要专业度人员分析 无埋点虽然可以对数据做提前收录,以防未来所需,但全数据,在页面上报与数据存储,都会对页面性能与数据库增加压力。 最大的一个问题,就是无法个性化定制上传的数据
此方案更多的贴合一线公司去实施落地
前端页面监控
性能监控
性能监控指的是监听前端的性能,主要包括监听网页或者说产品在用户端的体验。常见的性能监控项包括:
1.不同用户,不同机型和不同系统下的首屏加载时间
2.白屏时间
3.http 等请求的响应时间
4.静态资源整体下载时间
5.页面渲染时间
6.页面交互动画完成时间
performance.timing api 可以获取浏览器在加载 -》渲染完成 的事件流程。
封装sdk上报,针对需要收录的页面,直接嵌入js 代码,统计分析页面性能。
在线检测工具
Chrome工具:lighthouse
六大指标
可在线检测生成文档,同时提供优化具体方向,看一下检测的六大指标
1.First Contentful Paint: It marks the time at which the first text or image is painted.
第一个内容丰富的绘画:它标记了第一个文本或图像的绘画时间。
2.Speed Index: It shows how quickly the contents of a page are visibly populated.
速度索引:显示页面内容的可见速度。
3.Largest Contentful Paint: It marks the time at which the largest text or image is painted.
内容最大的涂料:它标记了最大的文字或图像的绘制时间。
4.Time to Interactive: It is the amount of time it takes for the page to become fully interactive.
互动时间:页面完全互动所花费的时间。
5.Total Blocking Time: It is the sum of all time periods between First Contentful Paint and Time to Interactive.
总阻止时间:这是“第一个内容丰富的绘画”与“互动时间”之间的所有时间段的总和。
6.Cumulative Layout Shift: It measures the movement of visible elements within the viewport.
累积布局偏移:它测量视口内可见元素的移动
评分区间:【0-49(红色):较差】 【50-89(橙色):需要改进】 【90-100(绿色):良好】
具体的优化方案
可根据检测报告,有目的的进行网站优化提升
错误日志收集
常规脚本错误
/**
* @description window.onerror 全局捕获错误
* @param event 错误信息,如果是
* @param source 错误源文件URL
* @param lineno 行号
* @param colno 列号
* @param error Error对象
*/
window.onerror = function (event, source, lineno, colno, error) {
// 上报错误
// 如果不想在控制台抛出错误,只需返回 true 即可
};
//VS
window.addEventListener('error', (event) => {
// addEventListener 回调函数的离散参数全部聚合在 error 对象中
// 上报错误
}, true)
Promise 错误
window.addEventListener('unhandledrejection', (event) => {
console.log(event)
}, true);
// rejectionhandled
window.addEventListener('rejectionhandled', (event) => {
console.log(event)
}, true);
// 备选处理方案 window.onunhandledrejection / window.onrejectionhandled
框架错误
Vue.config.errorHandler = function (err, vm, info) {
// 框架级别的捕获错误
// 拦截分析 但不吞并,直接在丢出去,再接入日志监控服务统一上报入口进行上报。
// 例如 console.err(err) 再次抛出错误
}
请求错误监控
前端请求方案基本上就两种: ajax fetch,针对两种方式进行统一重写代理
大家常用的 axios ,只需在请求拦截器以及响应拦截器进行处理上报即可
axiosHttp.interceptors.response.use(
response => {
let resData
if (response.code === 1000) {
resData = response.data ? response.data : response
} else {
throw resData
}
return resData
},
error => {
throw error
}
)
资源错误监控
资源错误监控本质上和常规脚本错误监控一样,都是监控错误事件实现错误捕获
脚本错误参数对象 instanceof ErrorEvent,而资源错误的参数对象 instanceof Event
由于 ErrorEvent 继承于 Event ,所以不管是脚本错误还是资源错误的参数对象都 instanceof Event
优先判断脚本错误即可区分
window.addEventListener('error', (event) => {
if (event instanceof ErrorEvent) {
console.log('脚本错误')
} else if (event instanceof Event) {
console.log('资源错误')
}
}, true) // 回调函数是否在捕获阶段执行,默认是false,在冒泡阶段执行
日志服务在后端开发中必不可少,但在前端领域,日志服务,基本只存在于node服务承接一些微服务聚合业务的异常监控
其次前端异常问题,要比中间层错误更难捕获,不同机型,不同业务场景,很奇怪的业务边界。不可预期性,不可控制的设备 硬件,都会存在影响。日志的收集,可为排查问题带来更多的可能性
日志仍然是洞察力的主要来源
成熟日志库,可以借鉴日志库结合本身业务需求进行包装
log4js
Loggerr
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!