| 《从零开始搭建前端监控平台》 | |||
|---|---|---|---|
| 作者 | 陈辰 (贝壳) | 出版社 | 人民邮电出版社 | 
| ISBN | 9787115532626 | 出版时间 | 2020-04 | 
| 豆瓣网址 | 豆瓣图书 | 是否有电子版 | 异步社区 | 
| 阅读日期 | 2020-05-30 | 更新日期 | 2020-05-30 | 
| 相关链接 | https://github.com/LianjiaTech/fee | 备注 | 
按
从GMTC了解到贝壳的本书作者,后续知道出书了,电子书买了正版,公司图书角申购了实体书,权当支持了。

书中开源项目 Fee 网址是 https://github.com/LianjiaTech/fee
书籍细节
很多细节已经提前了解了,比如使用 performance api来监控页面性能,使用 onerror  addEventListener  unhandledrejection 等方式完成错误监控,可以使用开源的监控平台、也可以使用阿里云的日志服务来完成数据的管理。
这次着重看看贝壳开源监控平台的技术细节。
1 前端监控平台解决的问题
- 稳定性,错误监控
 - 性能监控
 
书中提到的 fee 项目 https://github.com/LianjiaTech/fee
收集到了数据可以怎么用?
- 分析用户画像,合理区分浏览器兼容版本
 - 了解用户实际场景是如何使用你的功能
 - 针对性性能优化
 - 还可以保证技术产出
 
2 我们就是产品经理
3 上报数据
上报数据的SDK架构可设计如下:

做一个SDK似乎很不错的样子。
错误类型数据
产生报错的原因很多:JS引擎报错、 Vue  React 框架报错、js解析报错等。
普通的 Error 对象 有三个属性 name message stack 栈
var error = new Error('这里报错了')console.dir(error)// Error 对象有三个属性 name message stack
贴一下 MDN里 error 部分:
| 属性 | 含义 | 举例 | 
|---|---|---|
| SyntaxError | 语法错误 | 语法有错 | 
| TypeError | 类型错误 | 错误地字符串push,使用数组方法 | 
| RangeError | 范围错误 | 数值范围,比如 array.length-1 | 
| ReferenceError | 引用错误 | 不var,直接get变量 | 
| EvalError | eval错误 | 历史遗留问题,忽略。 | 
| URIError | URL错误 | 调用 decoude encode 等方法时候的错误 | 
| Failed to load resource | 资源加载错误 | 访问资源错误。 | 
可以 <img onerror='handleError'> ,也可以 window.addEventListener('error') 这样。
加载跨域资源不报错,需要 后端允许跨域并且前端script标签添加 crossorigin 
具体细节可以看我的仓库:https://github.com/Otto-J/web-error-demo
sdk的基础代码
首先是全局监听 error ,同时避免和script里的onerror重复。这里使用监听而不是等号重写,是为了避免用户自定义了error事件收不到错误信息。
// 监听资源加载错误(JavaScript Scource failed to load)window.addEventListener('error', function (event) {// 过滤target为window的异常,避免与上面的onerror重复var errorTarget = event.targetvar errorName = errorTarget.nodeName.toUpperCase()if (errorTarget !== window && errorTarget.nodeName && LOAD_ERROR_TYPE[errorName]) {handleError(formatLoadError(errorTarget))} else {// onerror会被覆盖,因此转为使用Listener进行监控let { message, filename, lineno, colno, error } = eventhandleError(formatRuntimerError(message, filename, lineno,colno, error))}}, true)
然后,处理未捕捉到的 Promise.reject 
// 监听浏览器中捕获到未处理的Promise错误window.addEventListener('unhandledrejection', function (event) {handleError(event)}, true)
针对 vue的console.error 报错准备重写,做个拦截。这里
// 针对vue报错重写console.error// TODOconsole.error = (function (origin) {return function (info) {var errorLog = {type: ERROR_CONSOLE,desc: info}handleError(errorLog)origin.call(console, info)}})(console.error)
然后封装runtime错误日志,load错误日志
监控性能
使用 performance 对象获取常规性能指标。
网络性能监控,必要的时候把 performance.timing.toJSON() 和当前的 location.href 上报
这里具体的内容专门做一个总结。(to do)
啥时候触发,一般是 window.onload 
可以把 …performance.timing 和 host+pathname 上传
环境相关数据
除了性能数据,还要了解用户是什么样的。
通常需要下面的内容
| 指标 | 描述 | 作用 | 技术实现 | 
|---|---|---|---|
| pid | projectID 产品具体编号 | 方便区分不同产品 | 不同产品规划不同值 | 
| uid | userID 用户表示 | 识别用户,主要是去重和追踪 | 登录的找cookie,没登录模拟唯一值 | 
| sid | sessionID 本次登录操作 | 识别用户的本次登录 | cookie session中找 | 
| version | 产品版本号 | 分析产品迭代的问题 | 版本号 | 
| ua | userAgent 用户浏览器信息 | ||
| 开关类数据 | 产品的一些指标开关 | isDev是否是测试数据 | 
手动上报数据
自动上报解决通用代码错误。如果遇到逻辑错误,代码写的逻辑不对,就可以使用手动上报,用户有困惑就可以上报
用户行为数据
如何判断平均在线时长,一般是用户点击和下次点击之间的时间做累加。
每5秒打点一次,15分钟不动视为离线
流程错误数据
比如密码错误、验证码错误等。
如何上报
一般还是使用 gif 图片请求。
图片请求比get好防跨域,和其他资源相比,js会阻塞页面
图片使用 new Image 发出,不会阻塞,图片也小 1 x 1 透明 ,透明的小,经过对比,gif体积最小。
同样最小体积 bmp74字节,png67字节 gif43字节
var img = new Image()img.src=xxx
4 总体设计
做了一个整体设计,大致分层,分层设计好,可以划分职责:
- 展示层,用于数据的展示,比如图标、列表等
 - 服务层,数据的管理
- api系统层,负责api的实现
 - api权限层,权限判断
 - 公共组件层,服务基础插件,比如日志 数据库 定时任务等
 
 - 支撑层,也就是数据层,数据的清洗,加工等
 
5 数据处理
服务器日志:
- 用户产生数据
 - 日志搜集、消费、清洗
 - 数据流转
 
访问日志可以通过 nginx 来实现。
- 每次都会产生 access.log 日志
 
原本的格式 + 图片带来的数据
消息系统:
如果数量较大,不好管理,单机也不好维护海量数据,这里引入了 kafka ,它是一个可以在多个应用质检可靠地传输实时数据的管道。

看起来是,前端a推送给 kafka数据,然后会同步地告诉 其他节点,这是典型的kafka集群:
- 若干消息的生产者
 - 若干消息的消费者
 - 一个 zookeeper集群
 
具体的细节先略过,第一次听说。
启动和配置略过,感觉可以通过docker来完成
后面跳过了前端不熟悉的各种配置,甚至还有设计sql表。
watchDog是监控报警的指令
其他的跳过
6 服务搭建
利用node起一个后端服务,这里选的是express
基本的配置experss,分离配置文件,链接数据库
写了一堆接口实现,迅速略过
7 页面展示
这里启动了一个vue项目。
哦,router里可以设置 meata.title 来设置title,回头可以优化项目
使用的第三方开源组件:
- antv/data-set 库
 
其他迅速略过
8 监控平台的使用
如果实时阅读消息,可以引入邮件,机器人等
监控平台的挑战
- 一开始数据量小,后来数据量大,抽样不合理,只能全量存。
 - 数据量撑破数据库,一个表超过3000w数据,后来数据库自己维护,方便控制
 - 告警配置读库缓慢,使用redis做二级缓存
 - 搜索功能,从sql中抽离,后来上了 es集群,效果较好
 - 错误的多样性,改成用户自己选择错误类型
 
简单读后感
快速翻阅了一遍,对比之前看到的利用阿里云日志服务来做数据支撑,这本书细节更多,可供参考。
但大量的代码,让人看着头疼。
