数据埋点方案、监控方案

1,002 阅读2分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

TIP 👉 休言女子非英物,夜夜龙泉壁上鸣。——秋瑾《鹧鸪天·祖国沉沦感不禁》

前言

数据埋点方案、监控方案

代码埋点

代码埋点是最灵活,同时也是最耗时的一种方式。

一般大厂内部会封装自己的一套埋点上报的npm包, 提供给各业务线使用。

一般我们需要上报什么信息呢?

  1. 埋点的标识信息, 比如eventId, eventType

  2. 业务自定义的信息, 比如教育行业, 点击一个按钮, 我们要上报用户点击的是哪个年级

  3. 通用的设备信息, 比如用户的userId, useragent, deviceId, timestamp, locationUrl等等

一般怎么上报?

  1. 实时上报, 业务方调用发送埋点的api后, 立即发出上报请求

  2. 延时上报, sdk内部收集业务方要上报的信息, 在浏览器空闲时间或者页面卸载前统一上报,上报失败会做补偿措施。

无埋点

概念

无埋点并不是真正的字面意思,其真实含义其实是,不需要研发去手动埋点。

一般会有一个 sdk 封装好各种逻辑, 然后业务方直接引用即可。

sdk中做的事情一般是监听所有页面事件, 上报所有点击事件以及对应的事件所在的元素,然后通过后台去分析这些数据。

业界有GrowingIO, 神策, 诸葛IO, Heap, Mixpanel等等商业产品

实现

  1. 监听window元素
window.addEventListener("click", function(event){
    let e = window.event || event;
    let target = e.srcElement || e.target;
}, false);
  1. 获取元素唯一标识 xPath

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++;
        }
    }
};

获取元素的位置


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);