Web前端最新#稳定性-异常上报 前端异常埋点系统初探,前端组件化开发教程

学习分享,共勉

题外话,毕竟我工作多年,深知技术改革和创新的方向,Flutter作为跨平台开发技术、Flutter以其美观、快速、高效、开放等优势迅速俘获人心

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

/**

* 用到了hooks,done表示在打包完成之后

* status.compilation.outputOptions就是打包的dist文件

*/

apply(compiler) {

if (process.env.NODE_ENV == “production”) {

compiler.hooks.done.tap(“sourcemap-uploader”, async (status) => {

// console.log(status.compilation.outputOptions.path);

// 读取目录下的map后缀的文件

let dir = path.join(status.compilation.outputOptions.path, “/js/”);

let chunks = fs.readdirSync(dir);

let map_file = chunks.filter((item) => {

return item.match(/.js.map$/) !== null;

});

// 上传sourcemap

while (map_file.length > 0) {

let file = map_file.shift();

await this.upload(this.options.url, path.join(dir, file));

}

});

}

}

//调用upload接口,上传文件

upload(url, file) {

return new Promise((resolve) => {

let req = http.request(${url}?name=${path.basename(file)}, {

method: “POST”,

headers: {

“Content-Type”: “application/octet-stream”,

Connection: “keep-alive”,

},

});

let fileStream = fs.createReadStream(file);

fileStream.pipe(req, { end: false });

fileStream.on(“end”, function() {

req.end();

resolve();

});

});

}

}

module.exports = SourceMapUploader;

复制代码

错误上报

两种方式:

  1. img标签 这种方式无需加载任何通讯库,而且页面是无需刷新的,相当于get请求,没有跨域问题。缺点是有url长度限制,但一般来讲足够使用了。

  2. ajax 与正常的接口请求无异,可以用post

这里采用第一种,通过动态创建一个img,浏览器就会向服务器发送get请求。将需要上报的错误数据放在url中,利用这种方式就可以将错误上报到服务器了。

确定上报的内容,应该包含异常位置(行号,列号),异常信息,在错误堆栈中包含了绝大多数调试有关的信息,我们通讯的时候只能以字符串方式传输,我们需要将对象进行序列化处理。

  1. 将异常数据从属性中解构出来,存入一个JSON对象

  2. 将JSON对象转换为字符串

  3. 将字符串转换为Base64

后端接收到信息后进行对应的反向操作,就可以在日志中记录。

1621581164(1).png

function uploadErr({ lineno, colno, error: { stack }, message, filename }) {

let str = window.btoa(

JSON.stringify({

lineno,

colno,

error: { stack },

message,

filename,

})

);

let front_ip = “http://localhost:3000/error”;

new Image().src = ${front_ip}?info=${str};

}

复制代码

后端服务

用koa搭一个简单后台服务,代码比较简单,按功能拆开来讲

上传文件接口

文件流写入:

router.post(“/upload”, async (ctx) => {

const stream = ctx.req;

const filename = ctx.query.name;

let dir = path.join(__dirname, “source-map”);

//判断source文件夹是否存在

if (!fs.existsSync(dir)) {

fs.mkdirSync(dir);

}

let target = path.join(dir, filename);

const ws = fs.createWriteStream(target);

stream.pipe(ws);

});

复制代码

错误日志

使用log4js记录我们的错误日志,这个也是非常流行的日志插件了,直接贴代码。

log4js-node

const path = require(‘path’)

const log4js = require(‘log4js’);

log4js.configure({

appenders: {

info: {

type: “dateFile”,

filename: path.join(__dirname, ‘logs’, ‘info’, ‘info’),

pattern: “yyyy-MM-dd.log”,

encoding: ‘utf-8’,

alwaysIncludePattern: true,

},

error: {// 错误日志

type: ‘dateFile’,

filename: path.join(__dirname, ‘logs’, ‘error’, ‘error’),

pattern: ‘yyyy-MM-dd.log’,

encoding: ‘utf-8’,

alwaysIncludePattern: true

}

},

categories: {

default: { appenders: [‘info’], level: ‘info’ },

info: { appenders: [‘info’], level: ‘info’ },

error: { appenders: [‘error’], level: ‘error’ }

}

});

/**

* 错误日志记录方式

* @param {*} content 日志输出内容

*/

function logError(content) {

const log = log4js.getLogger(“error”);

log.error(content)

}

/**

* 日志记录方式

* @param {*} content 日志输出内容

*/

function logInfo(content) {

const log = log4js.getLogger(“info”);

log.info(content)

}

module.exports = {

logError,

logInfo

}

复制代码

错误解析

这个接口就是对上报的错误信息进行解析,得到错误堆栈对象 上面我们已经拿到colno为2319,lineno为1,接下来需要安装一个插件帮助我们找到对应压缩前的代码位置。

npm install source-map -S

复制代码

先读取对应的map文件(按filename对应),然后只需传入压缩后的报错行号列号即可,就会返回压缩前的错误信息。打个比喻:简单地说相当于一本书的目录,我们根据目录可以快速找到某一部分内容的页数

router.get(“/error”, async (ctx) => {

const errInfo = ctx.query.info;

// 转码 反序列化

let obj = JSON.parse(Buffer.from(errInfo, “base64”).toString(“utf-8”));

let fileUrl = obj.filename.split(“/”).pop() + “.map”; // map文件路径

// 解析sourceMap

// 1.sourcemap文件的文件流,我们已经上传

// 2.文件编码格式

let consumer = await new sourceMap.SourceMapConsumer(

fs.readFileSync(path.join(__dirname, “source-map/” + fileUrl), “utf8”)

);

// 解析原始报错数据

let result = consumer.originalPositionFor({

line: obj.lineno, // 压缩后的行号

column: obj.colno, // 压缩后的列号

});

// 写入到日志中

obj.lineno = result.line;

obj.colno = result.column;

log4js.logError(JSON.stringify(obj));

ctx.body = “”;

});

复制代码

image.png

数据存储 日志可视化

ELK前端日志分析

www.cnblogs.com/xiao9873341…

看了一下许多平台对错误日志的分析和可视化都使用了ELK,ELK在服务器运维界应该是运用的非常成熟了,很多成熟的大型项目都使用ELK来作为前端日志监控、分析的工具。我对运维这一块兴趣不大,有兴趣的可以自行搭建,整出来界面还是挺炫酷的。

而我又不想每一次都跑去服务器查看日志,于是想到了可以建个表来把错误信息给存起来。用起老三样koa+mongodb+vue,我们这项目就算是齐活了。(mongodb,yyds???,省去了建表许多功夫)

npm install mongodb --save

复制代码

新建一个文件db.js封装一下mongo连接,方便复用:

// db.js

const MongoClient = require(“mongodb”).MongoClient;

const url = “mongodb://localhost:27017/”;

const dbName = “err_db”;

const collectionName = “errList”;

class Db {

// 单例模式,解决多次实例化时候每次创建连接对象不共享的问题,实现共享连接数据库状态

static getInstance() {

if (!Db.instance) {

Db.instance = new Db();

}

return Db.instance;

}

constructor() {

// 属性 存放db对象

this.dbClient = “”;

// 实例化的时候就连接数据库,增加连接数据库速度

this.connect();

}

// 连接数据库

connect() {

return new Promise((resolve, reject) => {

// 解决数据库多次连接的问题,要不然每次操作数据都会进行一次连接数据库的操作,比较慢

if (!this.dbClient) {

// 第一次的时候连接数据库

MongoClient.connect(

url,

{ useNewUrlParser: true, useUnifiedTopology: true },

(err, client) => {

if (err) {

reject(err);

} else {

// 将连接数据库的状态赋值给属性,保持长连接状态

this.dbClient = client.db(dbName);

resolve(this.dbClient);

}

}

);

} else {

// 第二次之后直接返回dbClient

resolve(this.dbClient);

}

});

}

// 增加一条数据

insert(json) {

return new Promise((resolve, reject) => {

this.connect().then((db) => {

db.collection(collectionName).insertOne(json, (err, result) => {

if (err) {

reject(err);

} else {

resolve(result);

}

});

});

});

}

//查询 –

find(query = {}) {

return new Promise((resolve, reject) => {

this.connect().then((db) => {

let res = db.collection(collectionName).find(query);

res.toArray((e, docs) => {

if (e) {

reject(e);

return;

}

resolve(docs);

});

});

});

}

}

module.exports = Db.getInstance();

复制代码

然后就可以在项目中愉快使用

let db = require(“./db”);

log4js.logError(JSON.stringify(obj));

//插入数据

await db.insert(obj);

ctx.body = “”;

复制代码

数据插入成功???

增加一个查询接口:

router.get(“/errlist”, async (ctx) => {

let res = await db.find({});

ctx.body = {

data: res,

};

});

复制代码

为了丰富错误信息,我们还可以在上报的时候增加报错时间,用户浏览器信息,自定义错误类型统计,引入图表可视化展示,更加直观地追踪

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

html5

);

ctx.body = {

data: res,

};

});

复制代码

为了丰富错误信息,我们还可以在上报的时候增加报错时间,用户浏览器信息,自定义错误类型统计,引入图表可视化展示,更加直观地追踪

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

html5

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值