Node.js躬行记(4)——自建前端监控系统

  这套前端监控系统用到的技术栈是: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是下载界面),既没有表、行等概念,也没有固定的模式和结构,所有的数据以文档(一个对象)的形式存储。但其使用方式和关系型数据库相似,并且还支持对数据建立索引,适用于高并发读写、海量数据存储和实时分析等。

Node.js躬行记(4)——自建前端监控系统

图1

  注意,在安装时默认会下载MongoDB Compress(一个可视化的MongoDB工具),默认下载会非常慢,建议自行下载,该工具的界面还是蛮清爽的,如图2所示。

Node.js躬行记(4)——自建前端监控系统

图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所示。

Node.js躬行记(4)——自建前端监控系统

图3

  用弹框的形式来创建项目,使用了Ant Design的Model、Form等组件,如图4所示。

Node.js躬行记(4)——自建前端监控系统

图4

3)性能分析

  在第一个折线图标签中的过滤条件包括项目、字段、日期等,性能指标按平均值呈现,可看到每个性能指标的趋势,如图5所示。

Node.js躬行记(4)——自建前端监控系统

图5

  按分时日统计性能平均数,在MongoDB中计算。原先创建日期是以时间戳的形式存储的,为了便于使用Aggregate,改成字符串形式。碰到一个坑,MongoDB中的Date类型采用的是格林尼治时间,而不是当前时区的时间,也就是说存在数据库中的时间会比当前时间早8小时。

  在第二个列表标签中,可以详细看到每条记录的信息,包括代理、网络等,便于在了解趋势的前提下,获悉更为细节的内容,如图6所示。

Node.js躬行记(4)——自建前端监控系统

图6

  点击ajax那一列,可弹出具体的异步请求信息,如图7所示。

Node.js躬行记(4)——自建前端监控系统

图7

4)错误分析

  有三个标签,第一个也是折线图,描绘的是某个时间的错误个数;第二个是错误列表,会给出具体的错误信息,如图8所示。

Node.js躬行记(4)——自建前端监控系统

图8

  第三个是饼图,饼图主要体现的是发生错误的浏览器分布情况(如图9所示),点击某一块可查看浏览器的具体版本(如图10所示)。

Node.js躬行记(4)——自建前端监控系统

图9

Node.js躬行记(4)——自建前端监控系统

图10

 

 

【参考资料】
PerformanceTiming

unhandledrejection 处理没有显式捕获的 Promise 异常

狼书(卷2)

Node-区分环境

Koa从零搭建到Api实现—项目部署

koa如何连接MongoDB

Koa2进阶学习笔记

如何计算首屏加载时间 

Mongoose Schema Error: “Cast to string failed for value” when pushing object to empty array

Support for the experimental syntax ‘classProperties‘ isn‘t currently enabled

Template string failing with Cannot read property ‘range‘ of null

Disallow JSX props spreading (react/jsx-props-no-spreading)

TypeError: Cannot read property ‘range‘ of null from template-curly-spacing

echarts项目的优化

使用 happypack 提升 Webpack 项目构建速度

mac下的mongoDB的安装和启动

安装MongoDB报错 mkdir: /data/db: Read-only file system

$sum mongoose

 

Node.js躬行记(4)——自建前端监控系统

上一篇:Linux下自己和自己用各种方法进行文件的上传下载


下一篇:Docker(十六)-Docker的daemon.json的作用