前端早早聊大会,前端成长的新起点,与掘金联合举办。 加微信 codingdreamer 进大会专属内推群,赢在新的起跑线。前端
第十四届|前端成长晋升专场,8-29 即将直播,9 位讲师(蚂蚁金服/税友等),点我上车👉 (报名地址):node
在去年,有过一次文字版的分享,当时系统尚未彻底建设成型,你们能够结合这两篇一块儿看: 技术探索:60 天急速自研-前端埋点监控跟踪系统大浪子。react
本文为第五届 - 前端监控体系建设专场讲师 - Jimmy 的分享 - 简要讲稿版(完整版请看录播视频):小程序
从宋小菜的第一款 APP 上线至今已经 5 年左右时间,咱们的端应用类型也由 RN APP 逐渐过渡到 RN APP/PC/H5/小程序 等多种类型共存的状况,咱们从 19 年开始就开始研发本身的 埋点监控系统 并在 19 年年末初步成型上线一直运行到如今,此次分享我将从如下几个方面去介绍咱们是如何研发出现在的埋点监控系统的:
后端
首先来说一下咱们设计这个监控系统的设计思路。
微信小程序
前端监控的基本目的在咱们看来是如下几点:api
基于以上咱们对监控体系的思考,小菜前端在这 5 年中逐步完善了本身的监控体系,这差很少就是咱们监控体系的一个简单的发展史:
对于研发成本的考虑是形成上面发展史造成的根本缘由:promise
接下来就应该考虑如何设计这个系统了,系统包含埋点和监控两部分,因为本次主题是监控,因此这里就讲监控系统相关的基础模块:
浏览器
如下是系统目前的基础架构:
缓存
客户端目前覆盖到了 PC/H五、RN 应用、小程序,因为 node 应用还比较少应用到业务中,考虑到投入产出比,尚未进行 SDK 的研发。
日志处理通过三层:
这里即是第三层的日志处理:
如下则是展现监控系统中从数据上报到展现的整个数据流向全过程
接下来就简单讲一下 SDK 的实现
首先要考虑的是应该采集哪些数据
虽然是监控错误数据,可是有时候为了分析错误的造成缘由或者重现错误出现的场景,咱们仍是须要用到用户的行为数据的,所以须要采集的数据包括两方面:
用户行为数据:
错误数据
因为时间缘由,这里简单讲一下两个端的 SDK 的简单实现:
RN SDK
小菜的 RN 应用是比较纯粹的 RN 应用,因此 RN SDK 实现能够简单地分为两端:
JS 端
Native 端
代码展现
Promise.rejectionTracking 的代码展现
const tracking = require("promise/setimmediate/rejection-tracking");
tracking.disable(); tracking.enable({ allRejections: true, onHandled: () => { // We do nothing }, onUnhandled: (id: any, error: any) => { const stack = computeStackTrace(error); stack.mechanism = 'unhandledrejection'; stack.data = { id } // tslint:disable-next-line: strict-type-predicates if (!stack.stack) { stack.stack = []; } Col.trackError(stringifyMsg(stack)) } }); 复制代码
微信小程序 SDK
这里简单讲一下微信小程序 SDK 实现的两个方面:
网络请求
代理全局对象 wx 的 wx.request 方法:
import "miniprogram-api-typings"
export const wrapRequest = () => { const originRequest = wx.request; wx.request = function(...args: any[]): WechatMiniprogram.RequestTask { // get request data return originRequest.apply(this, ...args); // } } 复制代码
页面跳转
覆写 Page/Component 对象,代理其生命周期方法:
/* global Page Component */
function captureOnLoad(args) { console.log('do what you want to do', args) } function captureOnShow(args) { console.log('do what you want to do', args) } function colProxy(target, method, customMethod) { const originMethod = target[method] if(target[method]){ target[method] = function() { customMethod(…arguments) originMethod.apply(this, arguments) } } } // Page const originalPage = Page Page = function (opt) { colProxy(opt.methods, 'onLoad', captureOnLoad) colProxy(opt.methods, 'onShow', captureOnShow) originalPage.apply(this, arguments) } // Component const originalComponent = Component Component = function (opt) { colProxy(opt.methods, 'onLoad', captureOnLoad) colProxy(opt.methods, 'onShow', captureOnShow) originalComponent.apply(this, arguments) } 复制代码
接下来就讲一下咱们是如何作日志处理的:
首先展现一下日志处理模块(咱们称之为 log-transfer)的基本结构:
数据上报属于处理原始数据的第一层,包含如下特色
日志上报处理中有很多须要注意的要点,这里挑几点简单说一下:
接下来简单讲一下监控看板:
一线是监控看板的一些简单展现截图
看板的做用包括:
什么是 issue? 即对已经上报的同类型错误进行概括和总结之后抽象出来的数据,便于咱们对同一种的错误进行跟踪和处理。
Issue 存在明确的生命周期,这里展现的就是咱们的 issue 生命周期:
如下是一个错误详情的示例:
使用 source map 转换后的堆栈信息也会展示在错误详情中。
接下来说一下咱们是如何设计和开发报警控制模块的:
结构
首先是系统结构:
做用
错误信息特征
前面解释了什么是 issue ,可是没有说明 issue 是如何抽象出来的,这里给你们简单解释一下,以 JS 错误为例:
JS 错误咱们在上报时使用 Tracekit 进行标准化,从而获得具备统一结构的错误信息,而后据此判断和归类错误,参考字段包括:
如下是系统 ISSUE 的展现:
ISSUE 的每一次状态更新都会被记录下来
Kafka 的做用
Kafka 的做用主要包括:
为何不使用实时通讯(socketIO/RPC)?总的来讲是为了系统稳定性考虑
固然,Kafka 也有替代方案,如 Redis/RabbitMQ 等。
报警任务设计
报警任务设计在报警系统中属于比较重要的部分,咱们大体将其抽象成两大部分:
数据结构示例
下面给出一个简单的报警任务数据结构示例:
报警任务是能够人为设置和控制的
而后就是系统中最后的一个模块,任务执行模块(咱们称之为 Inspector):
任务执行器则比较简单,主要用于执行控制器分发的报警任务,查询上报的线上数据根据任务的判断规则生成相应的任务结果并经过 Kafka 返回给任务控制器,因为报警任务可能较多因此采用集群的方式部署,多节点分散任务压力:
最后再放出在以前给出的各模块之间的 数据流向图,不知道你们是否清楚一些了:
整个系统的主要模块和数据流通都在这张图上。
个人演讲就此结束,谢谢你们!
本文使用 mdnice 排版