基于vue3+vite+阿里云sls开发的一个简单的性能监控平台,可以进行用户行为分析,如:用户数量,热点页面访问量,访问时段,用户浏览器使用,分辨率等等数据,以及前端性能相关数据,如:页面加载时间,js报错相关信息,接口加载时间,接口调用次数等等。下面废话不多说,直接开始项目。
1.vue3+vite初始化项目
1. npm create vite 项目名称
2. cd项目名称
3. npm install 《安装项目依赖包》
4. npm run dev 《启动项目》
选择框架的时候选择vue+ts,完成之后就获得了一个基础版本的项目。大致目录如下:
你会发现script用到了setup语法糖,
第一次见到的小伙伴可能会一脸懵,这里先附上官网文档以及一份写的不错的setup语法糖,总结就是变量不用return了,组件不用注册了,props和emits换方法了,父组件要调用子组件内容,需要把子组件变量或者方法defineExpose({})出去,等等。
https://v3.cn.vuejs.org/api/sfc-script-setup.html#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95
https://mp.weixin.qq.com/s/-1VRzekOKvK4ymEN8mHAFg
vue3不再使用elementui,而是改成了element-plus,这点大家也要注意,附上官网:
https://element-plus.gitee.io/zh-CN/
element-plus自身支持国际化,有点比较麻烦的是里面的icon需要用到哪个,就要在文件里import哪个,没有原来方便了,可以使用注册全局组件的方法,把所有ICON注入:
import * as Icons from '@element-plus/icons'
Object.keys(Icons).forEach(key => {
app.component(key, Icons[key as keyof typeof Icons])
})
以上这些只是随意提一嘴,属于基础内容,打造前端性能监控平台,最主要的在于阿里云sls日志服务的使用。
也就是这个东西,开通服务,然后新建Project:
然后再新建一个Logstore
此时切记一定要打开WebTracking,这是专门为前端来采集信息的。最好打开永久保存。
创建完毕之后会问你是否立即接入数据,选择是,然后选择webTracking接入数据:
接入之后,阿里云的基本配置也就准备好了,下一步就是去我们的项目里进行埋点,并且使用阿里云的WebTracking SDK将埋点数据传到阿里云sls上。
这里附上官方文档地址:
https://help.aliyun.com/document_detail/31752.html?spm=5176.2020520112.0.0.377f34c0q0DTnF#h4--http-get-
这里我们尝试上传一个js埋点报错数据:
//监听页面Js报错
function injectJsError(){
window.addEventListener('error',function(event){
console.log('------addEventListener-error-------')
console.log(event)
let log = {
kind:'stability',//监控指标大类 稳定性
type:'error',//小类
errorType:'jsError',
message:event.message,
filename:event.filename,
position:`${event.lineno}:${event.colno}`,
stack:event.error&&event.error.stack?getLines(event.error.stack):'-'
}
SentTracker.sendMsg(log);
// console.log(log)
})
}
class SentTracker{
url;
xhr;
constructor(){
this.url = `https://${ProjectName}.${Endpoint}/logstores/${logstoreName}/track`;
this.xhr = new XMLHttpRequest;
}
//上报单条埋点信息
sendMsg(data = {}){
let extraData = getExtraData();
let logInfo = {...extraData,...data}
for(let key in logInfo){
if(typeof logInfo[key] === 'number'){ //如果是数字 需要转为字符串,阿里要求的传参格式
logInfo[key] = `${logInfo[key]}`
}
}
logger.send(logInfo)
}
//上报多条埋点信息
sendMsgs(data = []){
let extraData = getExtraData();
let logArr= [logInfo]
data.forEach((item)=>{
let logInfo = {...extraData,...item}
for(let key in item){
if(typeof item[key] === 'number'){ //如果是数字 需要转为字符串,阿里要求的传参格式
item[key] = `${item[key]}`
}
}
logArr.push(logInfo)
})
let body = JSON.stringify(logInfo)
this.xhr.open('POST',this.url,true);
this.xhr.setRequestHeader('Content-Type','application/json');
this.xhr.setRequestHeader('x-log-apiversion','0.6.0');
this.xhr.setRequestHeader('x-log-bodyrawsize',body.length);
this.xhr.setRequestHeader('x-log-compresstyp','lz4');
this.xhr.onload = ()=>{
console.log(this.xhr.response)
}
this.xhr.onerror = (error)=>{
console.log(error)
}
let newBody = {
"__topic__": topic,
"__source__": source,
"__logs__":logArr,
"__tags__": {
"tag": "日志标签"
}
}
this.xhr.send(JSON.stringify(newBody));
}
}
当监听到js报错的时候,项目就会自动把错误信息上传到sls里
当时我在想,如果我要统计后端接口的调用次数,那是不是每次调用接口都要往sls里发起一次请求,那对于我项目的性能不是会有很大影响么,但是sls其实也早就想到了这点,所以它有两个配置项:
opts = {
host: '',
project: '',
logstore: '',
time: 10, //10s内自动收集日志,10s发一次
count: 30, //最多收集30条
}
可以看到,他是可以自动收集埋点数据,然后每隔一段时间发起一次请求的。
我们再去看看阿里云日志库:
所有上传的埋点信息,都会存进去,可以理解为一张数据库表,下一步,就是把这些表数据收集整理,然后做成可视化图表就行了,只要会简单的sql语句就行。
这里有个坑,我当时按照文档用Js去查日志库里的数据,死活查不出来,后来才发现,必须用node.js去查才可以,这里附上node关键代码:
const ALY = require('aliyun-sdk')
var sls = new ALY.SLS({
accessKeyId: "", //阿里云访问密钥AccessKey ID。更多信息,请参见访问密钥。阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维。
secretAccessKey: "", //阿里云访问密钥AccessKey Secret。
endpoint: '', //日志服务的域名。更多信息,请参见服务入口。此处以杭州为例,其它地域请根据实际情况填写。
apiVersion: '2015-06-01' //SDK版本号,固定值。
})
const projectName = "" // 必选,Project名称。
const logstoreName = "" // 必选,Project描述。
// 查询日志。
function queryLog(query, callback) {
const param = {
projectName, // 必选,Project名称。
logStoreName: logstoreName, // 必选,Logstore名称。
from: query.from, // 必选,开始时间,精度为秒。
to: query.to, // 必选,结束时间,精度为秒
topic: query.topic, // 可选,指定日志主题。
query: query.query // 可选,查询的关键词,不输入则查询全部日志数据。
}
sls.getLogs(param, function (err, data) {
if (err) {
let obj = {
code: 500,
data: '',
msg: err
}
callback(obj)
} else {
let obj = {
code: 0,
data: data,
msg: 'success'
}
callback(obj)
}
})
}
然后通过前端调用后端Node的接口,前端就可以获取到日志库里面的数据了,node只是为了前端获取数据做一道中转而已。附上前端sql语句的示例
//获取js执行报错统计
let jsError = await getLogs(
proxy.$urlData.getLogs,
"* and kind : stability and type : error and errorType : jsError | SELECT message,url, count(url) AS PV where message!='null' GROUP BY message,url ORDER BY PV DESC"
);
此时一个性能监控平台就搭建好了: