数据埋点方案、监控方案
代码埋点
代码埋点是最灵活,同时也是最耗时的一种方式。
一般大厂内部会封装自己的一套埋点上报的npm包, 提供给各业务线使用。
一般我们需要上报什么信息呢?
- 埋点的标识信息, 比如eventId, eventType
- 业务自定义的信息, 比如教育行业, 点击一个按钮, 我们要上报用户点击的是哪个年级
- 通用的设备信息, 比如用户的userId, useragent, deviceId, timestamp, locationUrl等等
一般怎么上报?
- 实时上报, 业务方调用发送埋点的api后, 立即发出上报请求
- 延时上报, sdk内部收集业务方要上报的信息, 在浏览器空闲时间或者页面卸载前统一上报,上报失败会做补偿措施。
实现
无埋点
概念
无埋点并不是真正的字面意思,其真实含义其实是,不需要研发去手动埋点。
一般会有一个 sdk 封装好各种逻辑, 然后业务方直接引用即可。
sdk中做的事情一般是监听所有页面事件, 上报所有点击事件以及对应的事件所在的元素,然后通过后台去分析这些数据。
业界有GrowingIO, 神策, 诸葛IO, Heap, Mixpanel等等商业产品
实现
监听window元素
window.addEventListener("click", function(event){
let e = window.event || event;
let target = e.srcElement || e.target;
}, false);
获取元素唯一标识 xPath ```javascript function getXPath(element) { // 如果元素有id属性,直接返回//*[@id=”xPath”] if (element.id) {
return '//*[@id=\"' + element.id + '\"]';
} // 向上查找到body,结束查找, 返回结果 if (element == document.body) {
return '/html/' + element.tagName.toLowerCase();
} let currentIndex = 1, // 默认第一个元素的索引为1
siblings = element.parentNode.childNodes;
for (let sibling of siblings) {
if (sibling == element) {
// 确定了当前元素在兄弟节点中的索引后, 向上查找
return getXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (currentIndex) +
']';
} else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
// 继续寻找当前元素在兄弟节点中的索引
currentIndex++;
}
}
};
<a name="456da6de"></a>
## 获取元素的位置
```javascript
function getOffset(event) {
const rect = getBoundingClientRect(event.target);
if (rect.width == 0 || rect.height == 0) {
return;
}
let doc = document.documentElement || document.body.parentNode;
const scrollX = doc.scrollLeft;
const scrollY = doc.scrollTop;
const pageX = event.pageX || event.clientX + scrollX;
const pageY = event.pageY || event.clientY + scrollY;
const data = {
offsetX: ((pageX - rect.left - scrollX) / rect.width).toFixed(4),
offsetY: ((pageY - rect.top - scrollY) / rect.height).toFixed(4),
};
return data;
}
上报
window.addEventListener("click", function(event){
const e = window.event || event;
const target = e.srcElement || e.target;
const xPath = getXPath(target);
const offsetData = getOffset(event);
report({ xPath, ...offsetData});
}, false);