这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2。将性能和错误量化,解决业务和开发都不知道,只有用户知道的问题,提升业务稳定性。
因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统。其实在很早以前就有这个想法,当时已经实现了前端的参数搜集,只是后台迟迟没有动手,也就拖着。
- 目前完成的还只是个雏形,仅仅是搜集了错误和相关的性能参数。
- 后台样式采用了封装过的matrix。
- 分析功能还很薄弱,只是做了简单的演示,并且各种基础功能还有待完善。
- 后面打算强化数据分析,并且还要实现错误的回放机制,思路的话以前也调研过,参考之前的一篇文章。
现在的这个系统还只能算是个玩具,后期还需要雕琢雕琢。下面是这套系统的目录结构。
├── pingapple --------------------------------- 菠萝监控系统 │ ├── client -------------------------------- 系统的前端部分 │ ├── sdk ----------------------------------- 信息搜集代码库 │ ├── server -------------------------------- 系统的后端部分
一、SDK
1)primus.js
在之前的《前端页面性能参数搜集》一文中,详细记载了各类性能指标的计算规则,并整理到了primus.js中。
本次将在primus.js的基础上做适当的修改,包括删除代理、测速、资源信息等功能,改变部分性能指标的计算规则,例如从浏览器发起HTTP请求算起,忽略浏览器重定向的时间等。
2)错误处理
完善错误处理,将错误分成三类:runtime、load和Promise。在window的error事件中,处理前两种错误。像img元素载入的图片地址不存在,就会执行formatLoadError()函数;像变量未定义,就会执行formatRuntimerError()函数。
window.addEventListener("error", function (event) { var errorTarget = event.target; // 过滤 target 为 window 的异常 if ( errorTarget !== window && errorTarget.nodeName && LOAD_ERROR_TYPE[errorTarget.nodeName.toUpperCase()] ) { handleError(formatLoadError(errorTarget)); } else { handleError( formatRuntimerError( event.message, event.filename, event.lineno, event.colno, event.error ) ); } }, true );
将window绑定unhandledrejection事件后,就会在Promise被拒绝且没有reject的回调函数时触发。
window.addEventListener( "unhandledrejection", function (event) { // console.log('Unhandled Rejection at:', event.promise, 'reason:', event.reason); handleError({ type: ERROR_PROMISE, desc: event.reason, stack: "no stack" }); }, true );
3)初始化
由于要计算白屏时间,DOM时间等,所以位置不能随便放,得要放在head的最后面。
<head> <script> window.pineapple || (pineapple = {}); pineapple.param = { "token": "dsadasd2323dsad23dsada" }; </script> <script src="js/pineapple.js"></script> </head>
二、服务端
1)Koa
Koa是由Express原班人马打造的Web轻量框架,通过组合各种中间件来避免繁琐的回调函数嵌套,当前使用的版本是V2。
npm install --save koa
使用的Koa脚手架:koa-generator,创建项目的结构,并且在此基础上做了调整(目录如下所示)。暂时还不会用到静态资源和视图层。
npm install -g koa-generator
├── server --------------------------------- 服务端 │ ├── bin -------------------------------- 命令 │ ├── config ----------------------------- 配置目录 │ ├── controllers ------------------------ MVC中的逻辑层 │ ├── db --------------------------------- MVC中的数据层 │ ├── public ----------------------------- 静态资源 │ ├── routes ----------------------------- 路由 │ ├── utils ------------------------------ 工具库 │ ├── views ------------------------------ MVC中的视图层 │ ├── app.js ----------------------------- 入口文件
为了区分开发环境和生产环境,通过cross-env统一不同系统设置环境变量的方式。
npm install --save cross-env
package.json中的命令如下,添加了环境配置。
"scripts": { "start": "node bin/www", "dev": "cross-env NODE_ENV=development ./node_modules/.bin/nodemon bin/www", "prd": "cross-env NODE_ENV=production pm2 start bin/www" }
prd按字面意思应该是生产环境的命令,其中使用了pm2,默认没有安装。还没部署过Node.js,还不清楚里面有多少坑。
npm install --save pm2
2)MongoDB
MongoDB是一个开源的非关系型数据库(图1是下载界面),既没有表、行等概念,也没有固定的模式和结构,所有的数据以文档(一个对象)的形式存储。但其使用方式和关系型数据库相似,并且还支持对数据建立索引,适用于高并发读写、海量数据存储和实时分析等。
图1
注意,在安装时默认会下载MongoDB Compress(一个可视化的MongoDB工具),默认下载会非常慢,建议自行下载,该工具的界面还是蛮清爽的,如图2所示。
图2
在Mac上配置MongoDB比较麻烦,不像Windows那样一件安装,需要一些步骤,废了点力气才装好,下面是执行的命令。
sudo mongod --dbpath=/Users/pw/data
3)Mongoose
Mongoose是MongoDB的一个ORM(Object-Document Mapper,对象文档映射)工具,可在Node.js环境中执行,封装了MongoDB操作文档的常用方法,包括引入数据库连接(connect),定义模型(model),声明文档结构(scheme),实例化模型等操作数据库的方法。
npm install --save mongoose
借鉴了以前PHP数据分层的思想,单独分离出数据库的连接,并抽象通用的Model层(如下所示)。
const mongoose = require("./db"); class Mongodb { constructor(name, schema) { //声明结构 const mySchema = new mongoose.Schema(schema, { typeKey: "$type" }); this.model = mongoose.model(name, mySchema); } //保存 save(obj) { obj.created = Date.now(); //日期 const doc = new this.model(obj); return new Promise((resolve, reject) => { doc.save((err, row) => { if (err) { reject(err); return; } resolve(row); }); }); } } module.exports = { model: Mongodb, mongoose };
4)路由
由于发送的地址是一张gif图片,因此在处理路由时,返回本地的一张gif图,如下所示,图像地址得是绝对路径,否则无法读取。
router.get('/pa.gif', async (ctx, next) => { const ctr = new indexController(); ctr.collect(ctx); const url = path.resolve(__dirname, "../public/images/blank.gif"); ctx.body = fs.readFileSync(url); //空白gif图 });
5)代理分析
在接收参数的时候分析代理所带的信息,例如浏览器、操作系统、设备等。使用的是一个第三方库:UAParser.js,四年前就关注过,当时GitHub上只有1K多个关注量,现在已经翻了4倍。
npm install --save ua-parser-js
6)假数据
制作一套合适的假数据,新增命令“npm run data”,初始化数据,便于展示。
三、后台
1)UI
后台模板采用了之前封装过的Matrix,但不会依赖Bootstrap框架。
将整个页面分成五块,分别是导航、侧边栏、面包屑、底部栏以及主体。
安装react-router的history,用于路由。
npm install --save history
期间也会安装各类依赖包,例如不支持在类中直接声明属性等。
在使用的过程中,ESLint会不时的弹出各种错误和警告,期间就不停的修改问题或查找相关配置忽略部分限制。
后台的侧边栏和面包屑等部分,会随着URL的不同而发生状态变化,本来想用多页实现,但配置要改很多,就依然做成一个SPA,只是稍微做了些改动。
组件库采用了流行的Ant Design,调用了按钮、单选框、日期等组件。
npm install --save antd
图表库使用的是ECharts,目前只用到了折线图和饼图。在引用图表时,为了优化构建,采取了按需引用的手段。
npm install --save echarts
2)项目管理
首先建立一个项目,然后才能分析该项目的性能和错误,如图3所示。
图3
用弹框的形式来创建项目,使用了Ant Design的Model、Form等组件,如图4所示。
图4
3)性能分析
在第一个折线图标签中的过滤条件包括项目、字段、日期等,性能指标按平均值呈现,可看到每个性能指标的趋势,如图5所示。
图5
按分时日统计性能平均数,在MongoDB中计算。原先创建日期是以时间戳的形式存储的,为了便于使用Aggregate,改成字符串形式。碰到一个坑,MongoDB中的Date类型采用的是格林尼治时间,而不是当前时区的时间,也就是说存在数据库中的时间会比当前时间早8小时。
在第二个列表标签中,可以详细看到每条记录的信息,包括代理、网络等,便于在了解趋势的前提下,获悉更为细节的内容,如图6所示。
图6
点击ajax那一列,可弹出具体的异步请求信息,如图7所示。
图7
4)错误分析
有三个标签,第一个也是折线图,描绘的是某个时间的错误个数;第二个是错误列表,会给出具体的错误信息,如图8所示。
图8
第三个是饼图,饼图主要体现的是发生错误的浏览器分布情况(如图9所示),点击某一块可查看浏览器的具体版本(如图10所示)。
图9
图10