前端监控完成
This commit is contained in:
@@ -1,15 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="AppApiMonitor">
|
<section class="AppApiMonitor">
|
||||||
<ai-list>
|
<ai-list>
|
||||||
<ai-title slot="title" :title="$options.label" isShowBottomBorder/>
|
<ai-title slot="title" :title="$options.label" isShowBottomBorder>
|
||||||
|
<template #rightBtn>
|
||||||
|
<el-button @click="page.current=1,getStaData(),getTableData()">刷新</el-button>
|
||||||
|
</template>
|
||||||
|
</ai-title>
|
||||||
<template #blank>
|
<template #blank>
|
||||||
<el-row type="flex">
|
<el-row type="flex" class="topRow">
|
||||||
<ai-card title="接口异常分布">
|
<ai-card title="接口异常分布" headerPanel>
|
||||||
<ai-echart/>
|
<ai-echart class="sta" type="pie" :data="sta.distribution"/>
|
||||||
|
</ai-card>
|
||||||
|
<ai-card class="fill mar-l16" title="接口异常TOP10" headerPanel>
|
||||||
|
<ai-table :tableData="sta.top10" :colConfigs="top10Columns" :isShowPagination="false" tableSize="mini"/>
|
||||||
</ai-card>
|
</ai-card>
|
||||||
<ai-card class="fill mar-l16" title="接口异常TOP10"></ai-card>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
<ai-card panel>
|
<ai-card panel class="mar-t16">
|
||||||
<ai-search-bar>
|
<ai-search-bar>
|
||||||
<template #left>
|
<template #left>
|
||||||
<ai-select placeholder="状态码" v-model="search.status" :selectList="networkStatus" @change="page.current=1,getTableData()"/>
|
<ai-select placeholder="状态码" v-model="search.status" :selectList="networkStatus" @change="page.current=1,getTableData()"/>
|
||||||
@@ -18,11 +24,19 @@
|
|||||||
<el-input v-model="search.name" size="small" placeholder="搜索接口" clearable @change="page.current=1,getTableData()"/>
|
<el-input v-model="search.name" size="small" placeholder="搜索接口" clearable @change="page.current=1,getTableData()"/>
|
||||||
</template>
|
</template>
|
||||||
</ai-search-bar>
|
</ai-search-bar>
|
||||||
<ai-table :tableData="tableData" :colConfigs="columns" :pageConfig.sync="page" @getList="getTableData" :dict="dict"/>
|
<ai-table :tableData="tableData" :colConfigs="columns" :current.sync="page.current" :size.sync="page.size" :total="page.total"
|
||||||
|
@getList="getTableData" :dict="dict">
|
||||||
|
<el-table-column slot="expand" type="expand">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<ai-wrapper>
|
||||||
|
<ai-info-item labelWidth="100px" v-for="op in desConfigs" :key="op.prop" :value="row[op.prop]" v-bind="op"/>
|
||||||
|
</ai-wrapper>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</ai-table>
|
||||||
</ai-card>
|
</ai-card>
|
||||||
</template>
|
</template>
|
||||||
</ai-list>
|
</ai-list>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -44,15 +58,24 @@ export default {
|
|||||||
tableData: [],
|
tableData: [],
|
||||||
page: {current: 1},
|
page: {current: 1},
|
||||||
search: {},
|
search: {},
|
||||||
columns: [
|
sta: {top10: [], distribution: []},
|
||||||
{label: "状态码", prop: "status"},
|
top10Columns: [
|
||||||
{label: "接口地址", prop: "path"},
|
{label: "接口地址", prop: "path"},
|
||||||
|
{label: "次数", prop: "total", width: 80, align: 'center'},
|
||||||
|
{label: "创建时间", prop: "createTime", width: 160},
|
||||||
|
],
|
||||||
|
columns: [
|
||||||
|
{slot: 'expand'},
|
||||||
|
{label: "接口地址", prop: "path"},
|
||||||
|
{label: "状态码", prop: "status", width: 100, align: 'center'},
|
||||||
|
{label: "创建时间", prop: "createTime", width: 160},
|
||||||
{label: "错误信息", prop: "error"},
|
{label: "错误信息", prop: "error"},
|
||||||
|
],
|
||||||
|
desConfigs: [
|
||||||
{label: "终端", prop: "device"},
|
{label: "终端", prop: "device"},
|
||||||
{label: "页面", prop: "url"},
|
|
||||||
{label: "用户", prop: "userName"},
|
|
||||||
{label: "环境", prop: "nodeProcess"},
|
{label: "环境", prop: "nodeProcess"},
|
||||||
{label: "创建时间", prop: "createTime"},
|
{label: "页面", prop: "url", isLine: true},
|
||||||
|
{label: "错误信息", prop: "error", isLine: true},
|
||||||
],
|
],
|
||||||
networkStatus: [
|
networkStatus: [
|
||||||
{dictValue: 200, dictName: '200:成功'},
|
{dictValue: 200, dictName: '200:成功'},
|
||||||
@@ -74,15 +97,28 @@ export default {
|
|||||||
this.page.total = res.data.total
|
this.page.total = res.data.total
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
getStaData() {
|
||||||
|
this.instance.post("/node/monitorApi/sta").then(res => {
|
||||||
|
if (res?.data) {
|
||||||
|
this.sta = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getTableData()
|
this.getTableData()
|
||||||
|
this.getStaData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.AppApiMonitor {
|
.AppApiMonitor {
|
||||||
|
|
||||||
|
.sta {
|
||||||
|
width: 400px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,38 +1,67 @@
|
|||||||
/**
|
import http from "./request"
|
||||||
* 获取符合要求的请求
|
|
||||||
* @param entries 监测的请求对象
|
|
||||||
* @param type 设置满足条件的请求类型
|
|
||||||
* @returns {PerformanceEntry[]}
|
|
||||||
*/
|
|
||||||
const getRequests = (entries = performance.getEntriesByType('resource'), type = ['xmlhttprequest']) =>
|
|
||||||
entries?.filter(e => type.includes(e.initiatorType)) || []
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 观察者工具对象,用于前端接口监测
|
* 观察者工具对象,用于前端接口监测
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Observer {
|
class Observer {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.saveLogs(getRequests())
|
this.initXHRObserver()
|
||||||
this.ins = new PerformanceObserver((list, ob) => {
|
|
||||||
const watchLogs = getRequests(list.getEntriesByType("resource"))
|
|
||||||
this.saveLogs(watchLogs)
|
|
||||||
})
|
|
||||||
this.ins.observe({entryTypes: ["resource"]})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
saveLogs(list = []) {
|
static saveLog(item = {}) {
|
||||||
list.map(e => {
|
const api = {
|
||||||
if (!/sockjs/.test(e.name)) {
|
method: item.method,
|
||||||
const api = {
|
path: item.url,
|
||||||
status: e.responseStatus,
|
url: location.href,
|
||||||
path: e.name,
|
nodeProcess: process.env.NODE_ENV,
|
||||||
url: location.href,
|
status: item.status,
|
||||||
nodeProcess: process.env.NODE_ENV,
|
code: item.response?.code,
|
||||||
}
|
error: item.response?.code != 0 ? item.response?.data : null,
|
||||||
console.log(api)
|
device: navigator.userAgentData.platform
|
||||||
// http.post("/node/monitorApi/addOrUpdate", api)
|
}
|
||||||
|
if (!/(sockjs-node|hot-update|monitorApi)/.test(api.path)) {
|
||||||
|
if (!!this.timer) {
|
||||||
|
clearTimeout(this.timer)
|
||||||
}
|
}
|
||||||
})
|
this.pending = [this.pending, api].flat().filter(Boolean)
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
http.post("/admin/apiForward", this.pending, {
|
||||||
|
withoutToken: true,
|
||||||
|
params: {url: "http://dvcp.cunwuyun.cn/ns/node/monitorApi/addOrUpdate"}
|
||||||
|
}).then(res => {
|
||||||
|
if (res?.code == 0) {
|
||||||
|
this.pending = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initXHRObserver() {
|
||||||
|
const origin = XMLHttpRequest.prototype.open;
|
||||||
|
XMLHttpRequest.prototype.open = function (...args) {
|
||||||
|
let send = this.send;
|
||||||
|
let _this = this
|
||||||
|
let post_data = []
|
||||||
|
this.send = function (...data) {
|
||||||
|
post_data = data;
|
||||||
|
return send.apply(_this, data)
|
||||||
|
}
|
||||||
|
this.addEventListener("readystatechange", function () {
|
||||||
|
if (this.readyState === 4) {
|
||||||
|
// 请求后拦截
|
||||||
|
Observer.saveLog({
|
||||||
|
url: args[1],
|
||||||
|
status: this.status,
|
||||||
|
method: args[0],
|
||||||
|
data: post_data,
|
||||||
|
response: JSON.parse(this.response || null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
|
return origin.apply(this, args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,11 +149,11 @@ export default {
|
|||||||
checkAll: v => v.chooseList.length == v.tableData.length && v.tableData !== 0,
|
checkAll: v => v.chooseList.length == v.tableData.length && v.tableData !== 0,
|
||||||
page() {
|
page() {
|
||||||
return {
|
return {
|
||||||
...this.pageConfig,
|
|
||||||
current: this.current,
|
current: this.current,
|
||||||
size: this.size,
|
size: this.size,
|
||||||
total: this.total,
|
total: this.total,
|
||||||
pagerCount: this.pagerCount
|
pagerCount: this.pagerCount,
|
||||||
|
...this.pageConfig
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="ai-card" :class="{panel}">
|
<section class="ai-card" :class="{panel,headerPanel}">
|
||||||
<ai-bar v-if="!hideHeader" :title="title" v-bind="$attrs">
|
<ai-bar v-if="!hideHeader" :title="title" v-bind="$attrs">
|
||||||
<template #title>
|
<template #title>
|
||||||
<slot name="title"></slot>
|
<slot name="title"></slot>
|
||||||
@@ -23,7 +23,8 @@ export default {
|
|||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
hideTitle: Boolean,
|
hideTitle: Boolean,
|
||||||
panel: Boolean
|
panel: Boolean,
|
||||||
|
headerPanel: Boolean
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hideHeader: v => v.hideTitle || v.panel
|
hideHeader: v => v.hideTitle || v.panel
|
||||||
@@ -43,12 +44,16 @@ export default {
|
|||||||
padding: 12px 40px 22px;
|
padding: 12px 40px 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.panel {
|
&.panel, &.headerPanel {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
||||||
.ai-card__body {
|
.ai-card__body {
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aibar {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
colors () {
|
colors() {
|
||||||
if (this.theme === '0') {
|
if (this.theme === '0') {
|
||||||
return ['#2896FF', '#09DBFE', '#61FDB9', '#FFBB69', '#8429FF', '#ea7ccc']
|
return ['#2896FF', '#09DBFE', '#61FDB9', '#FFBB69', '#8429FF', '#ea7ccc']
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
theme () {
|
theme() {
|
||||||
this.refresh()
|
this.refresh()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user