安利背景:作为一名优秀的程序员,仅仅满足于无条件百分百空手接白刃PM提出的需求可还行?一句"这个功能是刚需"就想骗得我们加班成秃子?开启埋点,让我们用事实说话,用数据打脸(逃
所谓“埋点”,是数据采集领域(尤其是用户行为数据采集领域)的术语,指的是针对特定用户行为或事件进行捕获、处理和发送给服务器的相关技术及其实施过程。
三者在使用上的异同:无埋点相较于手动埋点是较新的技术、调用更简单、代码侵入型更低。可视化埋点使用户可以基于浏览器为页面可视化的元素添加监听事件。
功能 | 无埋点 | 手动埋点 | 可视化埋点 |
---|---|---|---|
需要添加基础代码 | 需要 | 需要 | 需要 |
添加监听事件 | 无需侵入业务代码 | 需要侵入业务代码 | 基于可视化页面添加 |
事件历史数据回溯 | 可以 | 埋点前的数据不可回溯 | 埋点前的数据不可回溯 |
事件的额外属性 | 基本不可以 | 可以 | 基本不可以 |
事件的分类报告 | 基本不可以 | 可以 | 基本不可以 |
无明确UI位置的事件监听 | 不可 | 可以 | 不可 |
就目前的技术来说,手动埋点能获取到数据更定制化、可配性更强,而无埋点与可视化埋点操作门槛更低,各有优势
主要是收集用户的行为、事件信息,不同角色关注的信息可能侧重不同。典型的应用场景有面向数字营销领域的分析,以及面向产品运营领域的分析。前者注重来源渠道和广告效果,后者更在意产品本身流程和体验的优化。而对于我们开发人员来说,可能更在意错误日志上报,与鉴别是否PM声称的刚需是不是自己YY的伪需求(哼
目前有很多第三方提供的埋点服务,可免费接入,入门成本低,可满足较通用的数据收集需求。
如谷歌提供的Google Analytics、百度统计等。 接入方式一般为接入第三方的sass,若担心数据被泄漏或内网环境使用,需选择私有化部署服务。若需要高级功能或定制化功能则需付费购买或选择自行开发
一个埋点系统主要由以下三部分组成,埋点SDK、数据存储与分析服务、数据看板。我们主要分析一个简单的埋点SDK如何实现
无论手动埋点还是无埋点,都需要在项目入口需要注入一段自执行代码,用来收集用户配置信息和进行pv/uv的默认收集;
import longan from 'longan';
longan.start({
project: 'sds',// 项目名称
source: 'http://sds.sf-express.com',// 需要监控的域名
additionalInfo: { loginUser: '恰饭大老爷', customerName: 'HuaWei' },//附加信息
cacheUplaod?: 10, // 表示缓冲上报、可缺省 int
});
在需要收集信息的各个事件函数中,嵌入事件上报代码
// 业务代码
function handleClick() {
// 埋点代码
longan.dispatch({
...config, // 基础配置
event: 'click',//事件类型
name: 'event1',//事件名称
});
}
为想要统计的元素添加标识,或默认统计所有元素的事件
// longan- 为标识
跟我思考以下几个问题
发ajax当然可以,但是存在跨域的可能,业界常用是通过请求img/scritp资源来避免跨域,至于用img还是script,这是一篇比较img/script的传送门。通过将收集的数据挂在img上请求就可以达成目的了
// 上传埋点信息
const sendRequest = (config) => {
config.route = window.location.origin + window.location.pathname;
config.createTime = (new Date().getTime()/1000).toFixed(0);
if (config.cacheUpload && Number(config.cacheUpload) < MAX_CACHE_UPLOAD_NUMBER + 1 && Number(params.cacheUpload) > 0) {
// 缓存上报
recordCacheLog(params);
} else {
// 直接上报
const image = new Image();
image.src = UPLOAD_URL + '?' + parseParams(params);
}
}
pv -> page view页面的访问量
uv -> user view用户的访问量, uv可以通过pv筛user处理得出
如果不是单页面就很好办,每当页面onload就上报一次事件就可,重点在单页面如何监听history变化
// 监听onload事件 + history对象变化,发送pv
const listenHistory = (params) => {
window.onload = function() {
params.route = getCurrentRoute();
params.createTime = getCurrentTime();
console.log(params);
sendRequest(params);
}
// 篇幅有限这里addHistoryListener挖个坑有机会连载再细说叭
window.addHistoryListener('history', function() {
params.route = getCurrentRoute();
params.createTime = getCurrentTime();
console.log(params);
sendRequest(params);
});
}
// 获取当前时间的秒级时间戳
function getCurrentTime() {
return (new Date().getTime()/1000).toFixed(0);
}
// 获取当前域名和路径
function getCurrentRoute() {
return window.location.origin + window.location.pathname;
}
对所有的可交互事件元素进行解析,获取它们的DOM path,对页面上所有的DOM上的用户操作行为进行监听,当有操作行为(交互事件)发生时,自动调用事件上报函数。这样做有一个缺点就是信息冗余,我选择给想要统计的元素添加标识id来针对性统计,尽量降低代码侵入
export const EVENT_PREFIX = 'longan-';
// 监听全局事件埋点
const listenTriggerEvent = (config) => {
document.addEventListener('click', (e) => {
if (e.target.id && e.target.id.startsWith(EVENT_PREFIX)) {
const eventName = e.target.id.split(EVENT_PREFIX)[1];
const eventContent = e.target.innerHtml || '';
const payload = {
...config,
type: 'event',
client: navigator.userAgent,
content: eventName + eventContent,
};
//上传埋点信息fn
sendRequest(payload);
}
});
}