使用 Typescript 开发小程序前端错误及性能监控 SDK - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
alex1504
V2EX    分享创造

使用 Typescript 开发小程序前端错误及性能监控 SDK

  •  
  •   alex1504 2021-06-08 10:12:22 +08:00 2192 次点击
    这是一个创建于 1586 天前的主题,其中的信息可能已经有所发展或是发生改变。

    poster

    前言

    上篇文章分析了web 端错误及性能监控 SDK的实现方式,本篇则聚焦于小程序。尽管微信小程序本身就自带了监控能力,但如果我们需要更完善的数据,比如在出错时展示更多的信息如函数调用栈、行为轨迹、缓慢请求等,则需要自己去监控收集。

    原来在开发这套前端监控 SDK 时,我将 web 和小程序的监控糅合在了一起,但后来发现平台差异使得同一个模块产生很多异化的逻辑,甚至在初始化的时候也要增加环境的判断,这种异化的处理降低了后续的可维护性,因此最终还是将 SDK 拆分成两套。

    在开发小程序监控 SDK 时,首先明确的是,SDK 需要提供什么样的能力,或者说帮助我们获取什么数据。由于要获取的数据上篇已提及,这里看看我们设计的小程序端的 SDK 需要提供什么能力。

    SDK 提供的能力

    基础监控

    • 错误监控:包括 js 、promise 、http
    • 性能监控:页面性能

    附加能力

    • 缓慢 HTTP 请求监控
    • 用户行为轨迹监控
    • 错误过滤、错误抽样(本篇不作介绍,SDK 已实现)

    SDK 在最终使用上依然采用基于事件订阅的方式,下面分析下这些能力在小程序端如何实现

    错误监控

    使用小程序生命周期提供了 onError,重写 Page 即可

    App = function (appOptions) { appHooks.forEach((methodName) => { const originMethod = appOptions[methodName]; (appOptions as any)[methodName] = function (param: any) { const error = param as Error; if (methodName === "onError") { monitor.handleErrorEvent(TrackerEvents.jsError, error); } return originMethod && originMethod.call(this, param); }; }); return originApp(appOptions); }; 

    对于 promise 错误,小程序提供onUnhandledRejection,但官方文档指出此事件当前在安卓平台并不会生效,因此需要做一下 hack 处理,通过 console 的劫持进行判断

    export function rewriteConsole(monitor: Monitor) { for (const key of Object.keys(console)) { if (key in console) { const methodName = key as KeyofConsole; if (typeof console[methodName] !== "function") { continue; } if (!hackConsoleFn.includes(methodName)) { continue; } const originMethod = console[methodName]; console[methodName] = function (...args: any[]) { /** * 若是安卓手机则在此捕获 unhandled promise rejection 错误 */ if (args[0] === "Unhandled promise rejection") { const error = args[1] as Error; monitor.getSystemInfo().then((res) => { const isNeedEmit = hackUnhandledRejectionPlatform.includes( res.platform ); if (isNeedEmit) { monitor.handleErrorEvent(TrackerEvents.unHandleRejection, error); } }); } originMethod.call(this, ...args); }; } } } 

    性能监控

    使用小程序提供的 performance api

    export function observePagePerformance(monitor: Monitor): void { const canIUse = wx.canIUse("Performance"); if (monitor.performanceData.length) return; if (!canIUse) { return; } const performance = wx.getPerformance(); const observer = performance.createObserver( (entryList: WechatMiniprogram.EntryList) => { const performanceData: PerformanceData = entryList.getEntries(); // ,,, } ); observer.observe({ entryTypes: ["render", "script"] }); } 

    HTTP 监控

    拦截 wx.request 取值,并且对 options.success 及 options.fail 进行重写

    export function interceptRequest(monitor: Monitor) { const originRequest = wx.request; Object.defineProperty(wx, "request", { configurable: false, enumerable: false, writable: false, value: function (options: WechatMiniprogram.RequestOption) { const originSuccess = options.success; const originFail = options.fail; options.success = function (...args) { }; options.fail = function (...args) { }; return originRequest.call(this, options); } }); } 

    用户行为轨迹

    在小程序中,用户行为轨迹我定义为以下类型,并用队列保存:

    • 函数调用
    • console 信息
    • http 请求
    • 页面元素点击
    • 埋点行为(自定义行为)
    export enum IBehaviorItemType { fn = "function", cOnsole= "console", http = "http", tap = "tap", custom = "custom" } 

    我们通过重写 API 就能获取以上的信息

    • 函数调用:重写 App,重写 Page
    • console 信息:重写 console
    • http 请求:重写 wx.request
    • 页面元素点击:重写 Page

    值得注意的是,SDK 要监控页面元素点击仍需要我们做些手动工作。

    由于小程序不存在 dom,并不具备类似 web 提供window.addEventListener的能力,通过重写 Page 只是为了给 PageOptions 注入一个事件处理方法onElementTrack,因此在页面根节点需要对元素做事件绑定才能触达 SDK 收集。

    // index.wxml <view class="container" catchtap="onElementTrack"></view> 

    自定义行为

    某些情况下,你需要收集特定地方的埋点行为,只需要在埋点处调用 pushBehavior 方法即可。

    public pushBehaviorItem(item: IBehaviorItem): IBehaviorItem { if (!item.type) { item.type = IBehaviorItemType.custom; } if (!item.time) { item.time = Date.now(); } const { queueLimit } = this.$options.behavior; if (this.behavior.length >= queueLimit) { this.behavior.shift(); } this.behavior.push(item); return item; } 

    小程序 SDK 完整代码实现:欢迎 star 、fork 、issue 。

    https://github.com/alex1504/femonitor-wx

    component
        1
    component  
       2021-06-08 14:11:24 +08:00
    star 支持一下
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3656 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 04:22 PVG 12:22 LAX 21:22 JFK 00:22
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86