自动采集编写(大转转FE公众号埋点文章的详细说明书! )
优采云 发布时间: 2021-11-22 11:17自动采集编写(大转转FE公众号埋点文章的详细说明书!
)
自动埋点采集程序-概述介绍
自动埋点采集计划因涉及内容分三篇文章
其余两篇文章请于2020年11月5日至9日在富裕公众号查看文章。
大转转FE公众号二维码在文章末尾
本文文章篇幅较长,对最终效果感兴趣的同学可以先在“后台预览”部分查看截图
痛点
埋点,作为追踪业务上线效果的核心手段
文档也是重中之重,但是很多公司或团队都在用最原创的方式维护
即使有的团队有统一的埋地平台,整体运营成本也更高
1)维护成本
每次提出需求,PM需要花费大量时间维护嵌入点文档
添加新的埋点也可以,直接添加即可。
老埋点如有删改,一定要先跟开发同学确认,再更新文档
如果你怕麻烦,你可以只添加文件而不删除它们。. 好久不见~
2)埋点文件谁来维护?
前面说了,加法没问题,主要是删除或者更新埋点。谁来推动埋点文档的更新?
培养同学促进pm?
pm 找开发更新列表?
直接开发更新埋点文档?
开发同学需要在开发的同时记录埋点和更新列表吗?
开发和pm会吵架吗?
3)无阻塞进程
整个过程中,单靠一个角色真的很难达到目的
最终,不管谁来维护,如果没有阻塞过程,一切都变得有意识了。
靠自觉,如果能坚持下去,那就是地狱了~
4)埋点文档不准确
由于之前的原因,文档的嵌入点和实际的报表代码越来越远。
时间长了自然是看不到了,尤其是遇到人事变动或者业务调整的时候
新来的学生接手后,额头上直接出现了三道黑线。.
5)开发同学抵抗力强
PM:“帮我查一下xx项目的埋点,我急用”
PM:“你能帮我查一下我之前做过的xx活动的埋点吗”
PM:“需求的最后一次迭代,更新列表并给我一份副本”
...
尤其是赶上倒置的项目。.
作为FE,你有同感吗?.
想法
无论如何,在线数据是通过嵌入点反馈的,业务调整的基础是数据
这是客观事实。
因此,必须解决埋藏一些文件的痛点。
有同学可能会问,为什么不用第三方的埋点方案(比如:growingIO、Shence等)
因为,无论采用哪种方案,目前主流的上报埋点方法有两种:
全埋点上报(含区域上报) Active SDK上报(单埋点、多采购点上报)
全埋点上报需要根据页面结构配置PM(主要维护者在PM)。一旦页面结构改变,就需要重新配置。
另外,公司现状是有自己的数据平台,但是如果采用全嵌入式上报,数据分析层面的负担会非常沉重,而且每个业务线本身都使用代码主动上报方法。
如果SDK主动上报,就会遇到上述问题。
可能还有同学说:“这是PM应该做的,我只负责我的部分。”
这本身很好,但我们仍然希望提高整个团队的效率。
在做这个计划的时候,我们也和很多团队的pm沟通过,维护一个可用的embedding文档确实消耗了很多精力。
这也让我更加坚定了!
方案思路
前面所有问题的核心是两个:
经过群里多次讨论,将问题细分,对应的解决方法如下:
问题方案
看表格可能还是一头雾水,先来看看整体思路图
解释一下过程:
PM写埋点文档(仅供开发)fe根据文档写报告逻辑代码,上线执行build。这时候就触发了webpack。掩埋点被移除。插件被删除。上报埋点服务pm可通过埋点平台查看埋点及相应数据
过程很清楚了,但是肯定有一些问题,所以分开解释一下:
问题一:如何采集埋点
以vue项目为例,公示方法挂在Vue.prototype下:
Vue.prototype.$log = function (actionType, backup = null) {...}
如果举报页面pv,附加参数为频道号channel,即:
this.$log('PAGE_SHOW', { channel: 'xxx' })
解决方案:使用自定义jsdoc插件和自定义标签采集评论
/**
* @log 页面展现
* @backup channel: 渠道号
*/
this.$log('PAGE_SHOW', { channel: 'xxx' })
其中@log和@backup是jsdoc的自定义标签,这样jsdoc只监控$log方法也需要显式指定
因此,为了保持整个插件的行为一致,需要引入一个通用的配置文件js_doc.conf.js
js_doc.conf.js
module.exports = {
// 让jsdoc识别 @log
tag: 'log',
// 告知插件this.$log是发送埋点的方法,定义成数组是因为有的项目可能存在多个
method: ['$log'],
// pageType前缀,即会给项目pageType加前缀来区分不同项目
prefix: 'H5BOOK',
// pageType具体生成规则,不同项目可能规则不同
pageTypeGen: function({ prefix, routeName, dir, path, fileName }) {
return (prefix + routeName).toUpperCase();
},
// 公共的backup说明,最终单个埋点backup由公共的和私有的拼接而成
backup: 'uid:用户id',
// 项目信息,埋点上报用
projectInfo: {
projectId: '工程id,一般用项目名称',
projectName: '中文名称',
projectDesc: '项目描述',
projectIsShowOldMark: false // 是否展示老数据
}
}
这个配置文件是js_doc插件共享的,连同后面提到的文件依赖分析插件,以及自动添加的埋点标注工具。
js_doc插件的具体实现将在后续的“埋点自动采集方案-埋点提取”中具体说明。本文主要讲解整体方案的原理。
通过这一步,就可以成功采集到每个行为埋点,以及对应的注解和参数描述,即actionType和对应的注解
当然,要确定一个埋点,需要有两个核心因素
pageType 通常是在页面运行时引用当前页面路由来获取的,那么问题就来了。
问题二:编译时如何获取pageType
还有一个常见的情况,公共组件,如下图
一个组件被多个页面引用
或者组件 A 被辅助组件 B 引用,然后直接或间接引入页面。
那么组件A中的埋点一定要采集到对应的第1页和第2页。
如何才能做到这一点?
这个问题相当于:
解决方案:
这部分的具体实施方案将在《埋点自动采集方案-路由依赖分析》中具体阐述
例子:
// 附近的人
export default {
routes: [
// 首页
{
path: '/page1',
name: 'page1',
meta: {
title: '转转活动页',
desc: 'xx首页'
},
component: () => import('../views/page1/index.vue')
},
...
]
}
当然实际情况会很复杂:
复杂的写法可以通过ast语法分析兼容,但确实需要耐心~
至此,核心信息采集完成。
上一篇jsdoc部分:获取每个文件的所有actionType和对应的注释
而这一步又搞定了:项目的所有页面路由引用以及对应的组件文件依赖
页面描述的值:meta.desc || 元标题 || 姓名 || 小路
因为页面的描述和真实标题不一定相同,所以单独添加了一个desc字段
想一想,如果拿到了这些,就可以以页面为单位,在组织行为中埋藏一些数据了!
在访问过程中,我们也遇到了一个问题,那就是
不同业务pageType生成规则不统一
考虑到这个问题,我们在配置文件中定义了以下内容:
module.exports = {
...
// pageType前缀,即会给项目pageType加前缀来区分不同项目
prefix: 'H5BOOK',
// pageType具体生成规则,不同项目可能规则不同
pageTypeGen: function({ prefix, routeName, dir, path, fileName }) {
return (prefix + routeName).toUpperCase();
},
...
}
prefix:作为项目个性化前缀(主要用于区分不同的项目,因为不同的项目可能定义了相同的路由)
pageTypeGen:该方法用于业务定义生成pageType的规则。我们向用户返回prefix(项目前缀)、routeName(路由名称)、dir(文件目录)、path(路由)和fileName(文件名)。有了这些参数,基本上可以覆盖所有的路由生成方式。
OK,最终的数据结构形式:
{
// 项目所有页面
pageList: [
// 单个页面
{
// 该页面的路由信息
routeInfo: {
routeName: 'page1',
description: 'xx首页'
},
// 该页面对应所有的行为埋点
actionList: [
{
actionType: 'PAGE_SHOW',
pageType: 'H5BOOK_page1',
backup: 'channel: 渠道号',
description: '页面展现'
},
...
]
},
...
],
// 项目信息
projectInfo: {
projectId: '项目id',
projectName: '项目名称',
projectDesc: '项目描述信息',
projectMark: '项目标记',
projectLogsMark: '埋点标记',
projectType: '项目类型',
projectIsShowOldMark: false, // 是否展示老的埋点数据,默认false
projectDefBackup: '默认参数说明'
}
}
埋点采集完毕后,添加工程相关信息,然后通过界面批量上报埋点,后台保存。
埋在后台
我们使用eggjs + mongoose搭建后台服务
react + antd + bizChart(图表库)搭建的后端系统
背景预览
显示所有自动埋葬点采集项目的列表
点击显示item下所有页面(路由)的名称
点击显示本页所有埋点
同时查看单个埋点近7天的数据趋势
以上是方案的核心部分,但毕竟整个方案中解决问题的思路是技术驱动的
所以我们还要关心:如何让整个程序可持续运行?
问题三:如何保证埋点及时更新?
这个问题比较简单。既然webpack插件做好了,那么
解决方法:更新build命令,执行采集,上线时上报插件
埋点提取插件,webpack编译后,采集埋点后会自动上报。
确保每次上线时更新埋点文件。实时同步文档和代码
问题4:如何快速访问旧项目的埋点方案?
对于老项目来说,获取埋点是每个开发项目中最头疼的事情,尤其是埋点。
为此,我们还提出了一套便捷的解决方案
解决方法:通过命令行工具自动补全注释
我们写了一个命令行工具叫autocomment,全局安装
在项目根目录执行此命令,工具会自动添加src目录下的所有.vue、.js、.ts文件
命令工具和之前的插件使用通用的配置文件js_doc.conf.js
module.exports = {
// 让jsdoc识别 @log
tag: 'log',
// 告知插件this.$log是发送埋点的方法,定义成数组是因为有的项目可能存在多个
method: ['$log'],
...
}
读取里面的标签和方法属性。
自动给this.$log('xxxx', {...})的形式添加注释,没有注释方法
添加前:
this.$log('PAGE_CLOSE')
添加后
/**
* @log autocomment-PAGE_CLOSE
*/
this.$log('PAGE_CLOSE')
添加评论的逻辑很简单:
为什么要加固定前缀?
因为可以让开发的同学通过工具快速的找出哪些评论是自动添加的。
全局搜索''
同时为了消除开发同学的心理障碍(毕竟工具直接改成源码,心里还是不踏实)
为此,我们还添加了一个总结页面,添加评论后工具会自动弹出
用模仿git-history的风格通知开发同学我们改变了这些地方
问题5:开发过程中,如何保证埋点添加注释的规则得到遵守
因为是以笔记的形式采集的,开发同学很容易忘记写,那么
解决方案:提供监控加载器,实时检测开发
开发过程中,一旦发现调用了this.$log()方法,而且前面没有注释,直接在控制台报错
实现方法也是使用ast语法分析,复用之前的算法就够了,有异同。
注:埋点规格
细心的同学可能也发现,这个方案确实有几个局限性:
actionType 必须是字符串
如果是变量或表达式,则无法正常采集ast。
所以如果需要上报接口返回的内容,可以把值放在备份中。通过参数描述上报界面
不支持的场景:
// 错误演示1:
const resp = {...}
this.$log(resp.actionType)
// 错误演示2
this.$log(type === 1 ? 'actionType1' : 'actionTyp2')
如果遇到这种情况,就需要换个写法
// 错误演示1改进:
const resp = {...}
/**
* @log 内容上报
* @backup type: 数据类型
*/
this.$log('respData', { type: resp.actionType })
// 错误演示2改进:
if (type === 1) {
/**
* @log 行为埋点1
*/
this.$log('actionType1')
} else {
/**
* @log 行为埋点2
*/
this.$log('actionType2')
}
PS:就代码的美感而言,不好看。. . 但毕竟功能才是最重要的
另外,解决方案不支持动态添加路由
当然,支持它也不是不可能。如果需要,可以单独处理。
但是,对于ToC项目,一般的路由定义方法就足够了。
ok,这就是自动墓地采集程序的核心内容。
结束语
一开始,这个计划也和很多业务端开发的同学深入讨论过
其中,最受关注的问题有:
每个人面临的情况和合作方式都大不相同,真的没有办法一概而论。
但我们的初衷是提高协作的整体效率。
最起码可以省去团队维护文档的精力,思考更有价值的事情吧?
该方案目前在已对接团队中广受好评,确实解决了核心痛点。
我们相信:技术就是效率,技术和产品应该相互促进!