自动采集编写(大转转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,这就是自动墓地采集程序的核心内容。

  结束语

  一开始,这个计划也和很多业务端开发的同学深入讨论过

  其中,最受关注的问题有:

  每个人面临的情况和合作方式都大不相同,真的没有办法一概而论。

  但我们的初衷是提高协作的整体效率。

  最起码可以省去团队维护文档的精力,思考更有价值的事情吧?

  该方案目前在已对接团队中广受好评,确实解决了核心痛点。

  我们相信:技术就是效率,技术和产品应该相互促进!

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线