写点什么

腾讯基于 Proxy 的代码执行监听上报实践

  • 2020-03-05
  • 本文字数:3341 字

    阅读完需:约 11 分钟

腾讯基于 Proxy 的代码执行监听上报实践

随着移动设备的普及,兼容性和性能测试正在逐渐成为前端测试面临的两大挑战,再加上前端代码主要运行在客户设备上的特性,各种安全性挑战又层出不穷,我们该如何应对和解决?腾讯高级 Web 前端工程师樊东东在 GMTC 全球大前端技术大会(深圳站)2019 分享了 《基于 Proxy 的代码执行监听上报》,介绍了前端 SDK 基于 ES6 Proxy 的深度日志收集以及腾讯小程序前端测试案例。


本文根据演讲内容整理而成。


后端有全链路监控,能分析出模块之间的调用情况,前端一般日志打点、收集、上报,都是面条式的日志。在前端 SDK 的执行过程中能否收集更多更全面的信息?如 API 及回调函数的附属关系,API 和 API 间的上下文关系等。

一、需求背景

1. 打日志繁琐

日志是程序监控问题排查的重要手段。


如下是一段 SDK 实现和使用的例子:



作为 SDK 提供方,想要监控 SDK 运行情况,需要在各个 API 实现中打日志。


SDK 使用方使用 SDK 的时候需要在使用前后打日志。


能否统一处理 SDK 调用日志,让代码更少,日志更规范?

2. 线性日志可读性差

如下是上一段代码的调用日志。



这种日志线性无关联,只能体现时序。在排查问题时候分析这种面条式日志十分痛苦。


对于 API 的回调中有其他 API 调用这种 API 间依赖的关系,在日志中很难体现。


能否将日志进行可视化展示,且能体现日志间的上下文。



这种日志能帮助我们在不知道源码的情况下回溯 SDK 的调用过程,帮助重现和分析问题。

3. 属性监听

一般情况下,我们只对方法调用打日志,但在 QQ 小程序中一些组件(如 Video,对应的客户端组件)属性变化对应着客户端接口的调用。


这种对象属性的变化也想要追踪。

4. 目标

总结下,想在不改变 SDK 代码的情况下做到:


(1)统一上报入口;

(2)属性 get、set 上报;

(3)日志能体现上下文关系。

二、解决方案

defineProperty 和 Proxy 都能修改对象默认行为,进而进行监听。

1.defineProperty

defineProperty 是修改对象属性,如下是监听对象方法调用的例子:



defineProperty 有如下缺点:


(1)只能监听已有属性,无法追踪新增属性;

(2)需要深层遍历对象属性监听;

(3)原型的属性需要单独监听。


实现起来复杂,开发者对 SDK 的扩展无法监听到。

2.Proxy

(1)定义


Proxy 是 ES6 新增语法。在目标对象前架设一层拦截,可以对外界的所有访问进行过滤和改写。


(2) 功效


这是一段 Proxy 的例子:



利用 Proxy 可以:


  • 监听属性 get、set;

  • 结合函数包装监听方法调用。


这样能在不修改源码的情况下做到:


  • 统一监听入口;

  • SDK 使用者也能使用。

3. 问题

Proxy 是在原对象的基础上创建新的 Proxy 对象。需要考虑下面两个问题:


  • 能否替代原对象;

  • Proxy 性能。


(1) 原型比较



这段代码中有一个 Test 类,创建一个 Test 对象,对象上再创建 Proxy 对象。比较他们的原型和类型。


可以看到 Proxy 对象同原对象原型一致、类型一致。


(2) 属性比较



这段代码 Test 类中有属性 name,创建的对象新增属性 age 和方法 api2,对象上再创建 Proxy 对象。比较他们的属性。


可以看到 Proxy 对象和原对象属性相同


(3)代理 DOM 对象



在 Chrome 浏览器中,在 DOM 对象上创建 Proxy 对象,修改属性、调用方法会报错。


对于这种问题,可以用一个空对象做中转,如下所示:



  • 在空对象上创建 Proxy 对象;

  • 属性 get 取原 DOM 对象属性;

  • 属性 set 设置原 DOM 对象属性;

  • Proxy 对象的原型设为原 DOM 对象原型。


避免直接对 DOM 对象进行代理造成的使用报错的问题。


(4)总结


Proxy 对象和原对象有同样的原型、同样的属性,可以认为在使用上等同于原对象。

4. 性能

(1)运行性能


如下是原对象、Proxy 对象和 defineProperty 修改对象的属性 get、set 和方法调用的耗时对比。



从结果中看到,Proxy 对象的性能最低。算下来一次耗时不到 1 微秒。


不是高频调用,性能影响可以忽略。


起先大家也认为 Promise 性能低,但因为好用,Promise 还是流行起来了。


(2)上报性能


在实践过程中,对性能影响最大的是上报。比如小游戏中绘图 API 的高频调用,极大影响上报性能。


需要控制上报频率,方案如下:


  • 缓存一定数目再上报;

  • 黑名单内 API 不做上报;

  • 同一个 API 限制一定时间内上报次数;

  • 同一属性 get、set,同值只报一次。

三、API 上下文

如下是一段 API 回调中调其他 API 的例子:



想要在日志中体现代码上下文关系,需要关联如下关系:


  • API 调用;

  • API 回调函数;

  • 回调参数(API 结果)使用;

  • 回调中其他 API 调用。


然后通过根 API 将整个上下文关联起来。


下面我们来看下如何一步步对他们进行关联。

1. 关联 API

和其回调函数 API 和回调函数都是函数,可以在 Proxy 的属性访问时对他们进行函数包装。


对 API 进行包装:



API 的包装函数运行时可获得回调函数,对回调函数进行包装,将 API 对应的 ID 传递过去。



回调函数的包装函数运行时就能知道其属于哪个 API。


(1)踩到的坑


包装函数碰到下面两个问题:


  • 构造函数;

  • 事件监听。


构造函数


对象的方法可能会被当做构造函数使用。要能在方法的包装函数运行时知道其是被当做方法使用还是被当做构造函数使用。


如下图:



可以在包装函数中判断 this 的原型是否等同于包装函数的原型。


事件监听


取消事件监听的回调函数必须和事件监听的回调函数是同一个,才能取消成功。对函数进行包装会返回新的函数,导致取消事件监听无效。


可以对函数的包装函数进行缓存。避免事件监听与取消监听函数不一致的情况。


2. 关联回调函数和参数

回调函数的包装函数运行时生成对应 id,其参数如果是对象,则继续进行代理。参数的 Proxy 对象在使用时就能知道其从属于哪个回调函数。


3. 关联回调函数和其中 API

回调函数和 API 都是函数,关联回调函数和其中 API 本质上是要在函数运行时知道其外层函数。


(1)calleecaller 如下图所示:



  • 利用 callee 可以知道当前执行函数;

  • 利用 caller 可以知道当前执行函数外层函数;

  • 这样就能关联回调函数和其中的 API。


但在严格语法中 callee、caller 被禁止。


(2)栈


可以利用入栈出栈来模拟函数执行开始、执行完毕。



  • 回调函数的包装函数运行时生成 ID;

  • 回调函数 ID 执行前入栈,执行后出栈;

  • 内层函数运行时可通过栈尾 ID 知道外层函数。


如此可关联回调函数和其中的其他 API。


(3)setTimeout


setTimeout 将回调和其中其他 API 断开来了。setTimeout 中其他 API 可以认为是新开一个 trace。


如果想把 API 回调函数、回调函数中 setTimeout、setTimeout 回调函数、setTimeout 回调函数中其他 API 关联起来,可以把 setTimeout 当做 API 来处理。

四、可视化展示

zipkin 是一个开源的分布式链路追踪系统。可以用来做日志关联和可视化展示。


如图是 zipkin 所需要的日志数据结构:



只要有 traceId、ID 和 parentId 三个字段就能做日志关联并展示。


如图是前后端调用链路示意图:



后端的全链路是一个模块调另一个模块,前面的请求发送是后面请求接收的 parentId


前端的上下文是一个 API 的回调中有其他 API。API 调用可以看做回调的 parentId,回调可以看做其中其他 API 的 parentId。


根 API 的调用可以看做 traceId


这样就与 zipkin 所需要的数据结构对应起来了。


如图是 SDK 调用代码和对应的可视化界面



可以看到 API、回调和可视化界面中的日志一一对应。


这样在没有源码的情况下能通过上下文日志回溯调用过程,帮助复现和分析问题。

五、其他场景

Proxy 监听 SDK 的方法调用,能收集方法输入、输出。可用于单元测试,比对代码修改前后的日志,验证代码修改是否影响其他 API。


收集外网用户真实使用信息,补充测试案例。


统计 API 的调用次数。

六、总结

  1. Proxy 能追踪属性变化和方法调用;

  2. 日志能集中上报,SDK 使用者也能使用;

  3. 通过函数包装关联 API 和回调函数;

  4. 利用栈能关联回调函数和回调函数中其他 API;

  5. 日志从线性变为有关联关系的上下文;

  6. 借助全链路系统能可视化展示上下文,回溯调用过程。


作者介绍


樊东东,腾讯高级 Web 前端工程师,2014 年进入腾讯,先后经历过移动办公、泛娱乐产品、QQ 小程序的 Web 开发工作,有大量运营平台、H5、Node 等相关的开发经验;现负责 QQ 小程序开发者工具、小程序相关工具链、QQ 相关基础运营平台等开发工作。他善于在平凡的代码中找到不一样的玩法。


活动推荐


技术永不止步,精彩永不落幕,GMTC 全球大前端技术大会(北京站)2020 将于 6 月 05-08 日再次与大家见面,聚焦前沿技术及实践经验,强势输出更多大前端 & 移动开发领域的技术趋势与实践案例!


2020-03-05 17:422008

评论

发布
暂无评论
发现更多内容

详解 Apifox:批量添加接口请求 Body 参数的方法

Apifox

程序员 前端 后端 API body

软件测试学习笔记丨Web浏览器控制

测试人

软件测试

小智常见报表示例--层次坐标--条件汇总报表

小智数据

自定义报表打印控件 报表批量打印 小智开源报表工具

快速明白高校采购云管平台4大必要性

行云管家

云计算 云服务 高校 云管平台

MQTT & micro-ROS:构建高效的机器人应用

EMQ映云科技

物联网 机器人 mqtt emqx

从基础到高级应用,详解用Python实现容器化和微服务架构

华为云开发者联盟

Python Docker 微服务 华为云开发者联盟 企业号2024年7月PK榜

软件测试学习笔记丨测试用例流程设计

测试人

软件测试

小程序跨平台运行助力智慧社区,开拓多应用场景

Geek_2305a8

小智常见报表示例--层次坐标--组内占比报表

小智数据

自定义报表控件 小智开源报表 小智BI 报表打印 组内占比报表

观测云:多云监控的高效解决方案

可观测技术

Meme“吞噬”市场,VC项目失宠,加密市场下一步何去何从?

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

【YashanDB知识库】swap空间使用超大报错

YashanDB

yashandb 崖山数据库 崖山DB

观测云:数据驱动决策的智能分析平台

可观测技术

淘宝/天猫商品详情API接口与电商数据质量管理的结合应用

技术冰糖葫芦

API API 编排 API 文档 API 协议

【论文速读】| TCSR-SQL:面向表内容感知的自检索文本到SQL方法

云起无垠

Comparing WiFi Powerhouses: IPQ6010 vs IPQ5332

wallyslilly

qcn9274 IPQ5332

开发全方位体育直播平台的指南:从源码选择到多端实现

软件开发-梦幻运营部

软件测试简历书写、职业规划及面试的必备技能

测吧(北京)科技有限公司

测试

快手开源LivePortrait,实现表情姿态极速迁移,GitHub 6.5K Star

快手技术

人工智能 #开源 可灵 企业号2024年7月PK榜

拼多多商品详情数据接口全解析:获取商品信息的高效途径

tbapi

拼多多 拼多多API接口 拼多多商品详情数据接口

苏州企业如何通过IT外包实现降本增效?苏州IT外包案例分享

苏州服务器托管

IT外包公司 IT外包服务

解决多源异构数据整合难题"良策“,助企业高效管理数据资产

Aloudata

数据管理 Data Fabric 多源异构

MobPush REST API的推送 API之创建推送

MobTech袤博科技

Java 开发者 产品动态

南京大学携手和鲸、智谱,签署“101 数智领航计划”,共启人工智能赋能教育新篇章

ModelWhale

人工智能 数据科学 校企合作 智谱AI

小智常见报表示例--层次坐标--分组排名报表

小智数据

报表批量打印 自定义打印控件 报表打印 小智开源报表工具 分组排名报表

小智常见报表示例--层次坐标--逐层平均值报表

小智数据

类excel报表 自定义报表控件 报表批量打印 小智开源报表

小智常见报表示例--层次坐标--循环引用报表

小智数据

报表批量打印 自定义打印控件 小智开源报表

碳课堂|什么是碳标签?产品为什么要贴上“碳标签”?

AMT企源

数字化转型 双碳 碳管理 碳标签

安全与便捷并行,打造高效易用的用户支付体验

HarmonyOS SDK

HarmonyOS

AI 应用实战营 - 作业 五 - SD WebUI

德拉古蒂洛维奇

小程序引擎助力App实现小程序运行功能

Geek_2305a8

腾讯基于 Proxy 的代码执行监听上报实践_GMTC_樊东东_InfoQ精选文章