实时文章采集(一种兼容多平台的小程序日志采集方案(一))
优采云 发布时间: 2021-12-26 11:20实时文章采集(一种兼容多平台的小程序日志采集方案(一))
01
背景介绍
小程序,英文小程序。是一款无需下载安装即可在微信中使用的应用。用户可以扫描小程序代码或搜索小程序打开。触手可及,用完即可使用。无需担心是否安装过多应用程序。
据阿拉丁统计,截至2021年6月底,微信小程序数量突破430万,日活跃用户突破4.1亿。小程序深度影响了200+个子行业,11个主要平台推出了各自的小程序生态。小程序已经成为中国人定义的真正意义上的“互联网技术新标准”。
由于业务发展需要,我们在微信小程序、百度智能小程序、支付宝小程序、字节小程序、360小程序等多个小程序平台都有相应的上线。平台、系统、机型、版本兼容问题导致小程序上线问题;
思考:为什么小程序启动这么慢?为什么不能在线加载白屏数据?在线代码的质量如何?是否有任何错误?如何在网上快速查找和解决问题?用户做了什么?推出这么多平台小程序后,各个平台的效果如何?目前的小程序还有优化空间吗?
其实以上问题都可以通过日志文件分析来回答。每个小程序的后端也会采集
一些日志信息。比如微信后台采集
js异常日志和接口异常日志,但是接口异常日志只有状态码级别的信息和脚本异常日志。缺少当前异常发生时的页面路径信息、系统信息、网络状态、用户行为轨迹等信息的记录,因此排查起来相对困难。对于小程序性能数据的采集,各平台之间并没有统一的标准。所以我们需要一个兼容多平台的小程序日志采集
方案。
02
采集
理念
要采集
小程序的信息,首先需要了解小程序的基本架构设计。小程序本质上是混合体,但它们是有限制的。小程序的渲染层和逻辑层分别由两个线程管理:
这两个线程之间的通信是通过小程序的Native端传递的,逻辑层发送的网络请求也是通过Native端转发的。对于平台端,这种设计大大增加了平台对应用的控制,降低了各种风险。
当然,采集SDK也在逻辑层,所以可以监控逻辑层的交互响应。主流小程序的JS逻辑层开发主要依赖以下三个部分:
App:每个小程序都需要调用app.js中的App方法来注册一个小程序实例,绑定生命周期回调函数,错误监控和页面不存在监控等功能,整个小程序只有一个App实例,共享所有页面。Page:对于小程序中的每个页面,都需要在页面对应的js文件中注册,指定页面的初始数据、生命周期回调、事件处理函数等,简单的页面可以使用Page()来构造。wx:小程序开发框架提供了丰富的微信原生API,可以轻松调出微信提供的能力,比如获取用户信息、本地存储、支付功能。
因此,要想有效监控小程序的运行状态,就需要对这三个模块进行有效拦截。在小程序中,App、Page、wx 模块宏都暴露给全局。如果要拦截,可以直接改写全局中的变量。
03
总体方案
SDK用户包括小程序原生开发和小程序框架开发两种:
SDK 有两个主要功能:数据采集
和报告服务。SDK的主要功能是采集
小程序生成的日志。采集日志可以分为异常日志、正常日志和性能日志3种类型。每次上报日志时,也会上报1类通用信息:
日志类型
二级分类
操作说明
异常日志
JS错误、界面异常、资源下载异常
监控很关键,需要实时上报
正常日志
用户行为、日志信息、路由信息
日志量大,用户主动上报
性能日志
首屏时间、页面渲染时间、PV/UV
一次上报,同时统计PV/UV
一般信息
系统信息、用户信息、网络状态、场景值
其他 3 类日志的附加一般信息
我们的目标小程序涵盖目前主流的小程序,如微信、百度、今日头条、支付宝、360等。
公共日志采集
常规思维
通过相关API获取环境信息,主要包括以下几类信息:
多终端兼容思路
基本信息API与各个平台小程序的接口基本一致。主要区别在于模块宏的定义。比如微信小程序是wx,百度小程序是天鹅,今日头条小程序是tt。SDK初始化时,通过判断模块宏是否存在并存储在上下文变量中来确定当前的小程序环境,具体使用时通过上下文调用API。
public get context() {
if (this._context) return this._context;
if (typeof wx !== 'undefined') { this._context = wx; }
if (typeof swan !== 'undefined') { this._context = swan; }
if (typeof tt !== 'undefined') { this._context = tt; }
if (typeof my !== 'undefined') { this._context = my; }
if (typeof qq !== 'undefined') { this._context = qq; }
if (typeof qh !== 'undefined') { this._context = qh; }
return this._context;
}
// 使用示例 用户信息获取:ctx.getUserInfo()
当前页面的路径得到多终端兼容处理
所以这里有一个获取当前页面路径的方法,可以平滑各个平台小程序之间的差异。
public get currentPage() {
if (this.appName === 'qh') { // 360小程序兼容
const { path } = $router.history.current;
return path;
}
let pages = getCurrentPages();
if (pages.length > 0) {
return pages[pages.length - 1].route;
} else {
return this._indexPage;
}
}
异常日志采集
异常日志分为三种:脚本异常、接口异常、资源异常
由于小程序的特殊通信机制,接口请求和资源下载都是通过小程序载体Native进行转发和执行。因此,要采集
这部分异常,可以拦截wx.request、wx.download等相关API。
关于接口异常信息的上报,主要涉及两种情况: 在wx.request的成功回调中,如果响应状态码>=400,则表示网络请求已发送,但业务响应异常,并报告为异常。; 如果直接去wx.request的fail回调,说明网络请求异常,会进行异常报告;
资源异常主要用于拦截downloadFile文件下载API,下载失败时上报资源异常日志。
下面我们重点关注脚本异常的日志采集
。
脚本异常_常规思路
JS 中常见的错误有几种,其中类型错误、引用错误、未捕获的 Promise 错误发生的频率更高;其次是越界错误和不正确的 URI 错误。
前5个错误可以通过*敏*感*词*小程序App.onError采集
,Promise异常可以通过App.onUnhandledRejection API采集
,但是这个API在各个平台的支持是不一致的,如下:
脚本异常_多终端兼容思路
通过追踪异常栈,查看源码,我们可以看到微信已经通过try...catch把我们业务代码的外层包裹起来了。当发生异常时,通过console.error打印出来,所以在开发过程中,可以看到发生异常时,开发者工具控制台会打印异常信息。
因此,我们可以拦截console.error。本次拦截可以采集
到的异常包括:
实施过程中遇到的问题
在具体的实现过程中,我们发现不同平台的具体实现是不同的:
因此,截取console.error后,我们需要对截取的信息进行第二次处理,平滑平台差异。
具体的解决办法是通过正则匹配:
const ERROR_TYPES_REG = /(((Eval|Reference|Range|Internal|Type|Syntax)Error)|promise)
判断当前脚本异常类型,格式化信息后分别上报堆栈信息和错误内容。最终报告的脚本日志格式如下,包括错误类型、错误内容和堆栈信息。
"exceptions": [{
"errType": "MiniProgramError",
"content": "app.checkAuthorize1 is not a function",
"message": "TypeError: app.checkAuthorize1 is not a function",
"stacktrace": "MiniProgramErroranonymous> (httpe.p.__callPageLifeTime__ (h"
}]
性能日志采集
常规思维
通过官方提供的API获取数据并采集
和报告。微信提供wx.getPerformance() API,获取小程序启动耗时、页面渲染耗时、脚本注入耗时;但其他平台小程序不提供相关接口。
多终端兼容思路
用户点击小程序后,首先会下载小程序资源包。启动后会解析app.json文件,注册App(),然后执行APP的生命周期;然后开始加载页面,解析页面json文件,渲染.wxml文件,执行逻辑层js文件,调用页面生命周期。APP和页面的生命周期功能是性能日志采集
的重点。
生命周期钩子
等级
操作说明
主流小程序框架
360小程序框架
开机
应用级别
监控小程序初始化
支持
负载
展出
应用级别
监控小程序启动或切换到前台
支持
支持
负载
页面级别
监控页面加载
支持
支持
展出
页面级别
监控页面显示
支持
支持
准备就绪
页面级别
监控页面第一次渲染完成
支持
支持
隐藏
页面级别
监控页面隐藏
支持
支持
我们对比了各个平台小程序生命周期相关的API,发现主流小程序框架的实现基本一致。360小程序更特别。是基于Vue框架的二次封装,但大部分API还是一样的。在360小程序中,小程序初始化后的hook调用的是onLoad,需要特殊处理。
因此,可以通过拦截和管理小程序App和Page的相应生命周期来实现性能日志采集
。在性能日志采集
方案中,我们主要将其分为应用级性能和页面级性能。
应用级性能:我们定义了首屏时间,即进入小程序后第一页的渲染完成时间——SDK初始化时间。
由于小程序入口较多,有些是从分享卡进入,点击图标,搜索。不同的进入小程序的方式会显示不同的主页。因此,我们会在每个日志中携带当前页面入口路径。
页面级性能主要包括:
实现过程中遇到的问题在测试验证阶段,我们发现使用Taro框架开发转换的微信小程序无法采集页面级性能数据。经过具体定位,我们发现在Taro2版本中,小程序页面和组件被统一为Component组件。因此,需要拦截Component;在Taro3之后,小程序页面规范对象暴露在外,可以通过拦截Page来实现。具体实现逻辑如下:
private interceptPage = (): void => {
let self = this;
let isTaro = (typeof (process) !== 'undefined' && typeof (process.env) !== 'undefined' && typeof (process.env.TARO_ENV) !== 'undefined') ? true : false;
const primaryPage = Page;
if (isTaro) {
let primaryComponent = Component;
Component = (obj: any) => {
PAGE_LIFE_CYCLE.forEach(name => {
if (typeof obj.methods[name] === 'function') {
const primaryHookFn = obj.methods[name];
obj.methods[name] = function (info: any) {
return self.rewritePageLifeCycle(name, this, primaryHookFn, info);
}
}
});
primaryComponent && primaryComponent.call(this, obj);
}
}
Page = (obj: any) => {
PAGE_LIFE_CYCLE.forEach(name => {
const primaryHookFn = obj[name];
obj[name] = function (info: any) {
return self.rewritePageLifeCycle(name, this, primaryHookFn, info);
}
});
primaryPage && primaryPage.call(this, obj);
}
}
行为轨迹采集
如果只有一些比较隐蔽的错误的错误堆栈信息,排查起来会比较困难。如果有用户操作的路径,排查起来就容易多了。在行为轨迹日志的采集中,我们会采集APP函数栈、Page函数栈、HTTP请求栈,并上报最近10条行为轨迹日志,以帮助用户在发生异常时定位问题。
04
SDK特性
多终端、多帧适配
重量轻,支持多种模块化规格
SDK由Rollup打包,压缩体积49KB,支持cmj和es6模块化规范。
多种使用形式
1. 通过 npm 格式使用
import * as mpMonitor from 'mp-monitor';
mpMonitor.init({
projectId: '', // 项目标识
url: ''
});
2. 以单一文件格式使用
const mpMonitor = require('./utils/mp-monitor');
mpMonitor.init({
projectId: '', // 项目标识
url: ''
});
支持自定义报告日志
业务方可以使用console.error(\'自定义报告内容\')
05
商业实践
1. SDK现已完成集团北斗前端监控平台对接,支持微信、百度、今日头条、支付宝、QQ、360等多端监控;
2.截至2021.10.15,已接入13个小程序,覆盖5条业务线
3. SDK 上报模型与 Sentry 一致。自行搭建Sentry服务的企业可以直接使用SDK,配置上报url;
4. 平台接入效果展示
开发者可以通过首页的图表观察小程序当前的运行状态
通过性能图表,可以考虑当前小程序是否有优化空间。如果开启分包加载优化,当前首屏性能曲线应该会明显降低
观察从页面 URL 采集
的 pvuv 数据。优化业务代码时,可以考虑去掉pv为0的页面。
页面加载瀑布图,可以直观的看到一个小程序页面的加载过程
行为轨迹展示可以帮助开发者更快地重现在线问题,提高问题解决效率
06
总结
目前小程序日志采集SDK内部已经平滑了多平台之间的差异,统一了小程序性能数据采集指标。异常时上报页面路径信息、系统信息、网络状态、用户行为轨迹等相关信息,帮助开发者更快定位和解决在线问题。
我们会继续优化细节,完善功能。也欢迎有兴趣的同学一起交流。
对源码感兴趣的请点赞+转发+关注+私信【小程序日志采集
】。
欢迎点赞+转发+关注!您的支持是我分享的最大动力!!!