干货 | 破局传统埋点四大痛点!携程机票前端可视化埋点实践

作者简介

zy.jiang,携程前端开发专家,关注新技术与效能提升,热衷效率工具研发。

团队热招岗位:资深前端开发工程师

可视化埋点(Visual Event Tracking)作为一种广泛应用的用户行为数据采集方案,通过可视化界面配置页面元素与数据采集事件的关联关系,为传统代码埋点的痛点提供了有效解决方案。传统埋点模式存在开发周期长、沟通成本高、代码耦合严重、验证困难等问题,而可视化埋点通过可视化圈选、低代码采集等技术,可显著降低技术门槛和维护成本,提升迭代效率。

基于上述背景,我们研发了河图可视化埋点系统(以下简称河图),旨在提升埋点流程的效能,并简化埋点管理。河图现已融入公司内部的伏羲埋点管理系统(以下简称伏羲),作为其子系统,专注于可视化埋点领域,而伏羲则是一个集埋点开发、数据分析与管理于一体的综合系统。

本文首先系统对比两种埋点方案的实现差异,深入剖析可视化埋点在敏捷迭代与跨团队协作中的核心价值;其次,从架构设计与运行机制层面阐述可视化埋点如何系统性解决传统埋点的弊端;最后,围绕"从实现到可用"的主题,探讨通过规范化管理与技术优化构建高可用性埋点体系的最佳实践。

一、系统背景

埋点是一种非常重要的数据收集方式,主要用于收集用户行为和系统运行状况等数据。传统的手工埋点(代码埋点)流程图如下:

从上述流程图可以看出,传统代码埋点采用硬编码方式与业务逻辑紧密耦合,这种实现方式主要带来四方面问题:

1)周期长,迭代慢

  • 每次变更需经历完整发版流程

  • 无法实时调整,需求响应延迟

2)成本高,效率低

  • 需手动编写埋点代码,开发维护耗时

  • 埋点字段需多方确认,增加沟通成本

3)易出错,质量难控

  • 缺乏自动校验,存在参数类型错误风险

  • 人工编码可能导致关键字段遗漏

4)管理难,维护差

  • 埋点分散各业务代码,难以统一管理

  • 版本迭代后易被遗忘,形成了技术债

既然传统代码埋点存在以上诸多缺点,那么我们是否可以将流程中的手动开发埋点代码和手动测试埋点两个环节(图中开发与测试阶段)从开发周期中剥离出来,转变为通过可视化系统配置的方式实现,最终简化成如下图所示的流程:

可视化埋点通过"所见即所得"的配置模式,将埋点流程从代码中剥离至平台界面,可缩短上线周期并提升数据规范性。其核心优势在于:配置人员无需接触业务代码即可完成埋点管理,大幅降低开发成本,减少代码侵入性,同时实现规则实时生效,避免了包体积膨胀问题。接下来,我们将深入探讨可视化埋点的运作原理、操作过程和可靠性提升机制。

二、系统概览

河图可视化埋点系统在整个埋点生态中的定位及与其他系统的关系如下:

伏羲为河图提供了强大数据支持和可视化埋点管理分析等功能。

公共框架为河图提供了埋点基础数据,一些底层的埋点触发事件以及UBT(User Behavior Tracking,用户行为跟踪系统)上报基础API。

自动化测试平台和前端公共发布运维系统(以下简称mPaas)在数据验证与可靠性保障部分发挥了重要作用。

河图系统由以下三大核心部分组成:

1)河图SDK: 提供多端适配的SDK,尽管各端实现细节有所差异,但核心功能保持一致。

2)配置平台: 具备配置与管理可视化埋点规则的功能界面,并集成质量检查报告等辅助工具。

3)后台服务: 承担两大职责,一是建立SDK与配置平台间的通信桥梁,二是提供数据服务,支持对自定义埋点的深入分析等操作。

河图系统分层如下:

上图展示了河图系统的分层架构,其核心组件是河图SDK。以下是该SDK的主要特点:

1)简单接入:基于公司成熟的UBT SDK扩展构建,客户端只需接入河图SDK即可获得完整的埋点能力,包括规则管理、数据上报和埋点分布分析。

2)多端统一:虽然各端(Web/小程序/APP)底层实现不同,但提供完全一致的接口规范。一套配置即可实现多端数据采集标准化,大幅减少适配工作量。

3)代码无侵入:业务代码完全无需修改,开发过程无感知。SDK在编译阶段通过AST分析自动管理组件导入,开发者无需手动调整任何布局代码。

三、系统介绍

我们将对河图可视化埋点的原理以及配置平台的使用做详细介绍,它的总体流程包含以下几个步骤:

系统配置平台概览图如下:

上图展示了埋点配置的完整工作流:从元素圈选、规则编写到审批上线。接下来我们将深入探讨埋点配置的技术实现原理,以及如何通过配置平台落地这套埋点方案。

3.1 SDK模式介绍

SDK是可视化埋点的核心,负责实现元素的圈选、消息通信、规则适配、数据组装以及数据上报等功能。它支持四种运行模式,分别是:

1)配置模式:支持对埋点位置和触发条件进行规则配置,配置人员可以通过可视化界面灵活定义埋点规则。

2)验收模式:在规则配置完成后,可对待验收的埋点规则进行测试和验证,确保埋点的准确性和有效性。

3)上报模式:在满足规则条件时,SDK会自动组装并上报埋点数据,确保数据采集的实时性和准确性。

4)热力图模式:用于查看页面上埋点的热力分布情况,点击热力图可以查看具体埋点的详细信息,帮助分析用户行为。

由于篇幅限制,本文将重点介绍SDK如何接入以及四种模式中的配置模式和上报模式,这也是埋点从配置到生效的主要流程。

3.2 SDK原理及接入

可视化埋点SDK通过"编译时预处理+运行时拦截"的两个关键阶段工作:在编译阶段进行组件预处理,使其具备埋点能力;在运行时当满足埋点触发条件时,SDK会按配置规则处理数据并自动上报。它由两个核心功能部分构成:编译插件和核心包。

3.2.1 编译插件

编译插件在构建阶段发挥作用,主要完成两项关键工作:

首先,它通过包导入替换机制,将项目中引用的原始UI组件库(如React、React Native等)替换为对应的增强组件。这是一种非侵入式的组件增强方法,无需修改项目实际代码,只需在构建流程中引入该插件即可。例如:

js // 编译前,开发人员编写的代码: import { Text, Button, TouchableOpacity, TouchableHighlight } from 'react-native'
// 运行时代码与以下写法等效: import { Text, Button, TouchableOpacity, TouchableHighlight } from 'path/to/sdk/core'

用户可以通过配置文件指定需要增强的组件类型,同时插件也会基于默认配置处理常用交互组件。

其次,插件会优化项目的渲染时UI结构,特别是针对条件渲染场景。当业务逻辑判断某组件不需要渲染时,插件会在相应位置插入空占位组件,确保页面结构的稳定性。这种结构占位优化对于基于路径匹配的元素定位至关重要,能有效防止因条件渲染导致的节点索引不一致问题。实际测试表明,这种优化方案对页面性能几乎没有影响,同时有助于提高埋点的可靠性。

3.2.2 核心包

核心包是SDK的核心功能模块,为所有运行模式提供基础能力。其工作原理主要体现在两个关键环节:

首先,在配置模式下,核心包通过增强的UI组件拦截用户交互,提供元素圈选、属性提取和消息通信等功能。当用户与界面元素交互时,SDK会捕获当前节点及其父节点的完整属性数据,并通过消息通道实时发送给配置平台,由平台进行可视化规则编辑,最终生成结构化的埋点配置规则。下一章节会详细介绍配置模式下的具体实现。

其次,在非配置模式下(包括上报模式、验收模式和热力图模式),核心包主要负责: 

1)规则管理:页面初始化时自动拉取配置规则并建立索引 

2)触发拦截:通过增强组件精确识别各类用户交互时机 

3)数据处理:根据预配置规则组装、过滤目标数据 

4)上报队列:管理异步上报队列,支持批量发送和失败重试 

5)可视化支持:提供埋点分布热力图展示,便于分析用户行为热点

3.3 配置埋点

在配置阶段,为了实现端侧圈选与配置平台的实时交互,需要在端侧与配置平台之间建立实时通信机制。针对不同端侧,我们提供了多种通信方案:

Web端:

可以通过iframe内嵌或浏览器插件的形式,实现页面与配置平台之间的消息通信。web页面本身可以内嵌在配置平台中,也可以通过浏览器插件的形式,实现页面与配置平台之间的消息通信。

App端或小程序端:

对于App端或小程序端,我们采用云手机或扫码通信方案来实现配置平台与端侧的实时连接。接下来,我们将重点介绍扫码方式的实现过程,详细说明如何通过扫码建立端侧与配置平台的通信,并完成埋点配置的实时交互。

在扫码通信过程中,配置平台会生成一个包含唯一连接串的二维码。当已接入SDK的App扫描该二维码时,会使用这个唯一的连接串与配置平台建立实时通信。如下图所示,三种颜色分别代表三个不同的连接串。连接串作为消息路由的标识,服务器会将消息定向发送给具有相同连接串的客户端和配置平台,确保多个并发配置会话之间互不干扰。在消息推送实现上,系统支持WebSocket和SSE(Server-Sent Events)两种方案,为了有效降低网络开销,河图系统默认使用SSE方案。

用户的配置过程时序如下图所示:

以上这个图详细展示了用户配置埋点规则的时序。埋点配置的核心技术实现主要包含两个关键部分:定义埋点位置和配置上报规则。接下来我们将深入探讨这两部分的技术原理,以及如何结合配置平台实现高效的埋点管理。

3.3.1 埋点位置

可视化埋点位置,顾名思义,是指界面上一目了然的元素。它可以是具体的按钮、输入框、复选框等独立组件,也可以是一组井然有序的元素,例如列表项、Tab 栏、下拉框,甚至是某个节点的第几个子元素。

在配置元素时,首先需要对目标元素进行圈选。不同端采用不同的圈选实现方式:Web端通常在元素上层创建蒙层来突出显示选中区域,而在App端则倾向于直接为圈选元素添加高亮边框,这种方式实现相对简单。

当开启配置模式时,圈选元素后,元素上的属性数据通过消息服务推送到配置平台上,如下图左侧的埋点位置信息以及右侧的属性信息。

对于节点位置的配置,我们可以简单归纳为三种方案:

1)固定标识方案:如果埋点位置带有唯一标识(如 testID),我们可以直接使用该标识。例如,在编写 UI 自动化用例时,如果已经为元素预设了唯一的testID,那么直接使用它即可。这种方案稳定性较高,但需要在页面上统一添加标识,灵活性稍差。

2)相对路径方案:当埋点位置没有唯一标识时,可以使用节点路径来描述位置。不过,这种方案的稳定性较差,因为页面布局的变动可能导致路径失效,影响准确性。

3)混合路径方案:结合当前元素所在模块的 id 以及元素相对于模块的位置来描述。这种方案适合模块内部位置的描述,兼具灵活性与稳定性。

在实际生产环境中,混合路径的一个典型示例如下: 

/RCTView[S_FLT_N_List_Flight_Label_Infor_Actual_Total]/RCTView[1]/RCTView[0]/RCTView[0]/RCTView[0]/VetTouchableOpacity[0]

其中,

RCTView[S_FLT_N_List_Flight_Label_Infor_Actual_Total]

是具有固定testID标识的父组件,而后面的

/RCTView[1]/RCTView[0]/RCTView[0]/RCTView[0]/VetTouchableOpacity[0]

则是目标元素相对于该固定标识父组件的相对路径。这种混合路径方式通过固定标识父组件作为锚点,结合相对路径定位具体元素,使埋点配置在页面结构发生局部变化时仍能保持稳定。

补充说明:对于列表型元素,系统支持正则表达式匹配,只需配置一次即可覆盖所有动态生成的列表项,无需逐项设置。

下面,我们以三层结构示意说明位置描述(实际客户端可能涉及几十层关系)。

如上图所示,树状结构的最右侧叶子节点中,固定标识的路径最短,稳定性也最好。

注意:不同技术栈的节点元素名称可能不同。例如,Web 端有 div、span 等,而 RN 端则只有 view、touchableopacity 等组件名。在实际使用时,只需将图中的 node 或 leaf 替换为对应组件名即可。

在配置时,根据埋点位置的圈选方式,我们可以分为当前元素与同类元素:

当前元素:仅描述当前位置的元素路径,例如某个提交按钮或输入框。

同类元素:用于描述符合一定规则的一类元素,例如列表项、TAB、复选框等。如下图所示的航班列表页,每一项都有收藏点击位置(黄色五角星)。在任意一个收藏按钮上点击后,位置信息可填写为【第(\d+)条航班收藏入口】。运行时,SDK 会根据具体索引值匹配位置。

相对路径生成:

基于页面布局的元素树状结构,我们可以自定义一套相对路径生成规则。需要注意的是,不同客户端(如 iOS 和 Android)在生成相对路径时需保证一致性。

生成元素相对路径的实现方案有多种,例如 Web 页面的 DOM 树、React 的 Fiber 树,以及 Native 端的虚拟树等。我们可以根据元素在树中的位置生成相对路径。

以下以 React Native 页面为例,说明相对路径的生成过程:

根据 React Fiber 架构的原理,从当前 fiberNode 节点向上查找,并将经过的节点组合起来,形成路径。

如上图所示,当用户点击节点 LA 触发埋点时,系统会顺着 fiberNode 节点的 return 属性向上查找父节点,并记录这条链路上的所有节点信息,最终组合成相对路径。经过大量实践验证,路径长度达到 8 层时,已能在大多数场景下稳定描述元素的相对位置。因此,SDK 的默认配置将最大路径层级设置为 8。

8层路径示例如下:

/RCTScrollView[flightDetail_scrollView]/RCTView[0]/RCTView[0]/RCTView[0]/RCTView[0]/VetTouchableOpacity[1]

3.3.2 上报规则

上报规则定义了埋点数据的上报来源以及数据处理方式,包括筛选、组合、字段名称映射、取值路径设置等操作。数据来源可分为以下三种:

1)当前位置: 所需上报的数据已挂载在当前触发埋点的元素及其父级节点上,直接从中提取即可。

2)关联位置: 当所需数据无法从当前触发元素及其父级节点获取时,可通过规则配置关联其他节点。例如,在列表页项(绿框)被点击时,可关联获取出发城市和到达城市名称(红框)一并上报。

3)全局上下文数据:即SDK运行时的上下文数据,通常在App渲染后的某个生命周期中进行组装,供埋点上报时使用。

通过合理配置上报规则,确保埋点数据的准确性和完整性。

组装规则:

在上报过程中,原始数据需要经过一系列处理步骤,包括筛选、组合、字段名称映射以及取值路径设置,最终生成可上报的数据。用户可以通过拖放操作建立取值路径的映射关系。只有建立了映射关系的数据才会被上报,其他无关字段在运行时会被SDK自动过滤舍弃,从而确保上报数据的精准性和简洁性。

3.4 上报埋点

在埋点上报模式下,当当前元素命中上一节配置的规则后,便会触发埋点上报。下面以最常见的点击和曝光埋点为例,介绍可视化上报的具体流程。

以"点击"埋点为例:

1)拉取配置: 从服务端获取埋点配置规则。

2)用户点击: 用户触发页面元素的点击事件。

3)配置规则: 根据预配置的规则,确定需要上报的数据内容。

4)获取基础数据: 从当前元素或其关联位置提取所需的基础数据。 

5)组装上报数据: 对基础数据进行筛选、组合、转换、字段映射等处理,生成最终上报数据。

6)加入上报队列: 将组装好的数据加入上报队列,等待发送。 

7)ubt SDK上报: 通过UBT SDK将数据上报至服务器。

通过以下最简示例,说明SDK是如何从组件数据中筛选并组装最终的上报数据:

// 字段映射规则说明:// 参数名称: 取值路径payWay: child.props.nqhGuideTipsData.payWay  // 支付方式字段title: child.props.nqhGuideTipsData.title    // 立减方案字段
// 运行时触发埋点的组件实际数据结构{  props: {    testID: "第**航班",    nqhGuideTipsData: {      payWay: "分期",      title: "立减10元",      // ...其它字段(不会被埋点采集)    },    // ...其它字段(不会被埋点采集)  }}

在这个示例中: 

1)payWaytitle是我们配置的埋点参数名称 

2)child.props.nqhGuideTipsData.payWaychild.props.nqhGuideTipsData.title是对应的取值路径 

3)当埋点触发时,SDK会根据配置的取值路径从组件数据中提取对应的值 

4)最终只有配置的这两个字段会被采集上报,组件上的其他数据会被自动过滤

最终上报的数据格式如下:

{    payWay: "分期",    title: "立减10元"}

以上示例展示了点击事件触发时的数据处理流程。事实上,可视化埋点支持多种类型的事件采集,这些埋点的主要区别在于触发时机不同,例如页面进入、离开、元素输入、失焦、曝光等。尽管数据组装的流程略有差异,但整体思路相似。比如曝光埋点,Web端可以使用IntersectionObserver和MutationObserver;在React Native端则可以使用measure和measureInWindow等接口来检测元素位置。业界也有多种实现方案可供参考,例如通过Native底层监控所有变化的元素,生成一棵虚拟树,并通过对比新旧树的变化来识别曝光开始或结束的元素。网易曙光埋点系统就采用了类似的虚拟树对比方案。

携程内部Native框架团队已在底层对点击与曝光等埋点做了大量基础建设,提供了触发时机识别和基础数据组装等能力。河图SDK基于这些Native框架能力,通过侦听曝光时机,利用框架底层UBT接口上报可视化埋点相关数据。

四、从实现到可用

通过前文的阐述,相信读者已对可视化埋点的核心流程建立了系统理解。在实际落地过程中,我们积累了许多最佳实践,从数据获取扩展、上报稳定性保障、版本迭代维护,到条件渲染优化等多个方面,不断提升系统的可用性。下面我们将重点介绍其中几个关键实践:

4.1 数据获取扩展

在系统设计初期,可视化埋点仅支持从当前触发节点及其相关属性中获取数据。然而,在实际应用中我们发现这种单一的数据获取方式存在局限性:某些需要上报的数据可能并未在UI上呈现,或者分散在其他节点上。为了解决这个问题,我们对系统进行了两个方面的扩展:

1)多元素组合上报:支持从页面上其他非父子关系的元素上获取数据,将多个元素的数据组合形成一条完整的埋点记录。

2)全局上下文数据:在页面级别维护统一的埋点上下文数据,所有埋点配置都可以访问这些上下文数据并按规则筛选组装,特别适合处理那些UI上不可见但业务上需要的数据。

这两项扩展使系统能够更好地满足复杂业务场景的需求。

4.2 上报稳定性保障

针对配置拉取与匹配的强依赖特性,我们通过以下机制确保数据上报的稳定性:

1)异步队列与重试机制:当未成功拉取配置时,埋点行为会进入缓存队列等待,待网络恢复或配置拉取成功后按规则匹配上报。结合优化的接口重试机制(如指数退避策略),数据上报准确率可达代码埋点级别。

2)分批上报策略:为防止Native事件通道阻塞导致应用卡顿,系统会监控埋点数据量。当单次需要上报的埋点数据量过高时(如大量列表元素同时曝光),会采用200毫秒间隔的分批上报策略,确保应用性能的同时不丢失埋点数据。这个时间阈值可根据不同场景动态调整,实现性能与数据完整性的平衡。

3)跨页防丢失:针对页面快速切换导致的PageID漂移问题,通过页面生命周期监听与元素曝光状态双向校验,实现跨页埋点数据的精确关联。

4.3 版本迭代维护

为应对UI改版导致的布局变化,我们构建了覆盖全流程的防控体系:

1)版本灰度管控:配置规则与客户端版本强绑定,支持按版本号范围生效,避免新旧版本布局差异引发的规则失效。

2)发布卡口拦截:与自动化测试平台深度集成,在发版流程中,通过公司的mPaas平台自动检测埋点配置健康度(如元素匹配率、曝光覆盖率),若命中率低于预设阈值则阻断发布并告警。

3)数据健康监测:定期输出埋点质检报告,包含配置规则命中详情、失效原因分析及修复建议,驱动数据治理闭环。

4.4 条件渲染优化

在实际开发中,某些组件的条件渲染逻辑(如三元运算符)可能会导致页面元素结构随数据变化而改变,进而影响元素的相对位置描述。例如,当条件渲染的分支不同时,页面结构可能发生显著变化,导致埋点配置失效或数据不准确。

为避免类似上述问题,我们在编译阶段通过抽象语法树(AST)分析,对动态渲染的元素进行占位改造。具体来说,可以在条件渲染的分支中插入占位节点,确保页面结构在不同数据场景下保持稳定。这种方式不仅能够提升埋点配置的鲁棒性,还能减少因页面结构变化导致的埋点失效问题。

五、结语

综上所述,可视化埋点通过无代码侵入、实时动态生效和开发解耦等特性,显著提升了埋点效率。借助伏羲埋点系统的标准化输出和配置平台约束,确保了数据格式统一和字段完整性,同时降低了技术门槛,使非技术人员也能参与埋点配置。

然而,可视化埋点也存在一定局限性:复杂交互场景难以完全覆盖、非UI绑定数据获取受限、动态渲染结构变化带来稳定性挑战。因此,它并非替代其他埋点方式的全能解决方案,而是一种重要补充。在实际应用中,应结合多种埋点策略,取长补短,以满足复杂业务场景的数据需求,提升采集准确性和全面性。

【推荐阅读】

 “携程技术”公众号

  分享,交流,成长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值