技术调研:因不能使用已经成熟的其他插件,如FunDebug(收费),所以需要自己写一个。
实现要求: 将线上的(主要指前端)错误收集起来,动态在本地创建一个文件夹,每天一个文件(以时间命名),只保留7天内的文件
项目技术:Vue.config.errorHandler(项目是vue)
注意:ActiveXObject可以在本地创建文件,但是IE特有的,所以我选择通过node来做
实现:
import moment from 'moment'; import axios from 'axios'; let errorType = ''; const errorHandler = (error, vm, info) => { let { message, // 异常信息 name, // 异常名称 script, // 异常脚本 line, // 异常行号 column, // 异常列号 stack // 异常堆栈信息 script, line, column可以从这里面匹配到 } = error; console.log('抛出全局异常'); let now = moment().locale('zh-cn').format('YYYY-MM-DD HH:mm:ss'); let data = `${now} ${stack}type:${errorType}`; console.log(error, 'error'); axios.post('/error/errordata', data) .then(res => { console.log(res.data, '请求成功'); }) .catch(error => { console.log(error); }); }; let GlobalError = { install: (Vue, type) => { errorType = type; Vue.config.errorHandler = errorHandler; Vue.mixin({ beforeCreate() { const methods = this.$options.methods || {}; Object.keys(methods).forEach(key => { let fn = methods[key]; this.$options.methods[key] = function (...args) { let ret = fn.apply(this, args); if (ret && typeof ret.then === 'function' && typeof ret.catch === 'function') { return ret.catch(errorHandler); } else { // 默认错误处理 return ret; } }; }); } }); Vue.prototype.$throw = errorHandler; } }; export default GlobalError;
node
let h = require("http"); let fs = require('fs'); const url = require('url'); let path = require('path'); let moment = require('moment'); h.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('bug统计'); let parsed_url = url.parse(req.url); let errorname = ''; if (parsed_url.pathname === '/error/errordata') { //匹配路由 // 定义了一个post变量,用于暂存请求体的信息 let postData = ''; let date = ''; req.on('data', chunk => { //在on函数中获取请求体 postData += chunk; //请求数据过大时会自动进行多次请求 }) req.on('end', () => { //请求结束 res.writeHead(201, { 'content-type': 'text/plain' }); res.end(postData); let last7 = moment().subtract(7, 'days').format('YYYY-MM-DD'); date = postData.slice(0, 10); errorname = postData.split("type:")[1] + 'Error'; // date = "2020-06-24"; let newpath = `/Users/xxxxx/Desktop/${errorname}/`; // let newpath = path.join(__dirname, `../${errorname}/`) fs.exists(newpath, exists => { // fs.exists测试某个路径下的文件是否存在。回调函数包含一个参数exists,true则文件存在,否则是false。 if (!exists) { // fs.mkdir mode:目录权限(读写权限) 默认0777 fs.mkdir(newpath, 0777, err => { if (err) { console.log(err, '创建文件夹错误'); } else { fs.writeFile(newpath + `${date}.txt`, `${postData}`, null, err => { if (err) { console.error(err, '写入错误'); } else { console.log('写入成功'); } }); } }); } else { fs.exists(newpath + `${date}.txt`, exists =>{ if (exists) { fs.appendFile(newpath + `${date}.txt`, ` ${postData}`, 'utf-8', err => { if (err) { console.log(err, '追加错误'); return false; } console.log('追加成功!!!'); }); } else { fs.writeFile(newpath + `${date}.txt`, `${postData}`, null, err => { if (err) { console.error(err, '写入错误'); } else { console.log('写入成功'); } }); } }) } fs.readdir(newpath, (err, files) => { if (err) { return console.log('目录不存在') } files.forEach(item => { let time = item.slice(0, 10); // let isBefore = false; let isBefore = moment(time).isBefore(last7); if (isBefore) { fs.unlink(newpath + item, err => { if (err) { console.log(err, '删除错误'); return false; } console.log('删除文件成功'); }); } }); }) }); }) } }).listen(8888); console.log("服务器开启啦~~");
实现之后: