From 1d0603405f32a523a1eb4554f22caf5b3a712881 Mon Sep 17 00:00:00 2001 From: zhaozhenfang Date: Wed, 17 Jul 2024 16:38:05 +0800 Subject: [PATCH] feat: add metrics chart --- web/src/stores/charts.ts | 293 +++++++++++++++++++--- web/src/views/{ => echarts}/MyEcharts.vue | 180 +++++++------ web/src/views/echarts/chartTable.vue | 54 ++++ web/src/views/{ => echarts}/index.ts | 36 ++- web/src/views/nodeDetail.vue | 42 ++-- 5 files changed, 461 insertions(+), 144 deletions(-) rename web/src/views/{ => echarts}/MyEcharts.vue (74%) create mode 100644 web/src/views/echarts/chartTable.vue rename web/src/views/{ => echarts}/index.ts (81%) diff --git a/web/src/stores/charts.ts b/web/src/stores/charts.ts index 52a2906..ba3e0df 100644 --- a/web/src/stores/charts.ts +++ b/web/src/stores/charts.ts @@ -6,54 +6,120 @@ export const useLayoutStore = defineStore('layoutOption', { return { layout_option: [ { - x: 0, y: 0, w: 1, h: 1, i: '0', - static: false, display: false, title: 'CPU总使用率', + x: 0, y: 0, w: 2, h: 1, i: '0', + static: true, display: true, title: '运行时间', query: { - sqls: [{ sql: '100 - (avg(irate(node_cpu_seconds_total{instance="{macIp}",mode="idle"}[5m])) * 100)' }], + sqls: [{ sql: '(time()-node_boot_time_seconds{group="",instance="{macIp}"})/(60*60*24)' }], + type: 'value', range: false, isValue: true, interval: 5, + target: 'value_series', unit: '天', float: 2 + } + }, + { + x: 2, y: 0, w: 2, h: 1, i: '1', + static: true, display: true, title: 'CPU核数', + query: { + sqls: [{ sql: 'count(count(node_cpu_seconds_total{group="",instance="{macIp}",mode="system"}) by (cpu))' }], + type: 'value', range: false, isValue: true, interval: 5, + target: 'value_series', unit: '个', float: 0 + } + }, + { + x: 4, y: 0, w: 2, h: 1, i: '2', + static: true, display: true, title: '内存总量', + query: { + sqls: [{ sql: 'node_memory_MemTotal_bytes{group="",instance="{macIp}"}' }], + type: 'value', range: false, isValue: true, interval: 5, + target: 'byte2GB_series', unit: 'GiB', float: 2, + + } + }, + { + x: 6, y: 0, w: 2, h: 1, i: '3', + static: true, display: true, title: '当前打开的文件描述符', + query: { + sqls: [{ sql: 'node_filefd_allocated{group="",instance="{macIp}"}' }], + type: 'value', range: false, isValue: true, interval: 5, + target: 'num_series', unit: 'K', float: 2, min: 0, max: 9, + color: [] + } + }, + { + x: 0, y: 1, w: 2, h: 2, i: '4', + static: true, display: true, title: 'CPU总使用率', + query: { + sqls: [{ sql: '100 - (avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="idle"}[5m])) * 100)' }], type: 'gauge', range: false, isChart: true, interval: 5, target: 'percent_series', unit: '%', float: 2, min: 0, max: 100, - color: [ - [0.5, '#67e0e3'], - [0.8, '#E6A23C'], - [1, '#fd666d'] - ] + color: [{ + offset: 0, color: '#2988f1' + }, { + offset: 1, color: '#6bccff' + }] } }, { - x: 1, y: 0, w: 1, h: 1, i: '1', - static: false, display: false, title: '内存使用率', + x: 2, y: 1, w: 2, h: 2, i: '5', + static: true, display: true, title: 'CPU iowait', query: { - sqls: [{ sql: '(1 - (node_memory_MemAvailable_bytes{instance="{macIp}"} / (node_memory_MemTotal_bytes{instance="{macIp}"})))* 100' }], + sqls: [{ sql: 'avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="iowait"}[5m])) * 100' }], type: 'gauge', range: false, isChart: true, interval: 5, target: 'percent_series', unit: '%', float: 2, min: 0, max: 100, - color: [ - [0.8, '#67e0e3'], - [0.9, '#E6A23C'], - [1, '#fd666d'] - ] + color: [{ + offset: 0, color: '#965af2' + }, { + offset: 1, color: '#cc8dfa' + }] + } + }, + { + x: 4, y: 1, w:2, h: 2, i: '6', + static: true, display: true, title: '内存使用率', + query: { + sqls: [{ sql: '(1 - (node_memory_MemAvailable_bytes{group="",instance="{macIp}"} / (node_memory_MemTotal_bytes{group="",instance="{macIp}"})))* 100' }], + type: 'gauge', range: false, isChart: true, interval: 5, + target: 'percent_series', unit: '%', float: 2, min: 0, max: 100, + color: [{ + offset: 0, color: '#eb9509' + }, { + offset: 1, color: '#febf50' + }] + } + }, + { + x: 6, y: 1, w: 2, h: 2, i: '7', + static: true, display: true, title: '根分区使用率', + query: { + sqls: [{ sql: '100 - ((node_filesystem_avail_bytes{group="",instance="{macIp}",mountpoint="/",fstype=~"ext4|xfs"} * 100) / node_filesystem_size_bytes {group="",instance="{macIp}",mountpoint="/",fstype=~"ext4|xfs"})' }], + type: 'gauge', range: false, isChart: true, interval: 5, + target: 'percent_series', unit: '%', float: 2, min: 0, max: 100, + color: [{ + offset: 0, color: '#00c59d' + }, { + offset: 1, color: '#1de3cf' + }] } }, { - x: 0, y: 1, w: 3, h: 2, i: '2', - static: false, display: false, title: '系统平均负载', + x: 0, y: 3, w: 8, h: 3, i: '8', + static: false, display: true, title: '系统平均负载', query: { type: 'line', range: true, isChart: true, interval: 5, target: 'value_series', unit: '', float: 2, min: 0, max: null, sqls: [ { - sql: 'node_load1{instance="{macIp}"}', + sql: 'node_load1{group="",instance="{macIp}"}', start: startTime, end: endTime, series_name: '1分钟' }, { - sql: 'node_load5{instance="{macIp}"}', + sql: 'node_load5{group="",instance="{macIp}"}', start: startTime, end: endTime, series_name: '5分钟' }, { - sql: 'node_load15{instance="{macIp}"}', + sql: 'node_load15{group="",instance="{macIp}"}', start: startTime, end: endTime, series_name: '15分钟' @@ -62,28 +128,28 @@ export const useLayoutStore = defineStore('layoutOption', { } }, { - x: 0, y: 2, w: 3, h: 2, i: '3', - static: false, display: false, title: '内存信息', + x: 0, y: 3, w: 4, h: 3, i: '9', + static: false, display: true, title: '内存信息', query: { type: 'line', range: true, isChart: true, target: 'byte2GB_series', unit: 'GiB', float: 2, min: 0, max: null, sqls: [ { - sql: 'node_memory_MemTotal_bytes{instance="{macIp}"}', + sql: 'node_memory_MemTotal_bytes{group="",instance="{macIp}"}', start: startTime, end: endTime, step: 15, series_name: '总内存', }, { - sql: 'node_memory_MemTotal_bytes{instance="{macIp}"} - node_memory_MemAvailable_bytes{instance="{macIp}"}', + sql: 'node_memory_MemTotal_bytes{group="",instance="{macIp}"} - node_memory_MemAvailable_bytes{group="",instance="{macIp}"}', start: startTime, end: endTime, step: 15, series_name: '已用', }, { - sql: 'node_memory_MemAvailable_bytes{instance="{macIp}"}', + sql: 'node_memory_MemAvailable_bytes{group="",instance="{macIp}"}', start: startTime, end: endTime, step: 15, @@ -93,40 +159,187 @@ export const useLayoutStore = defineStore('layoutOption', { ] } }, - ], - process_layout_option: [ { - x: 0, y: 0, w: 3, h: 2, i: '0', - static: false, display: false, title: '***chart', + x: 4, y: 6, w: 4, h: 3, i: '10', + static: false, display: true, title: 'cpu使用率', query: { type: 'line', range: true, isChart: true, - target: 'byte2GB_series', unit: 'GiB', float: 2, min: 0, max: null, + target: 'percent_series', unit: '%', float: 2, min: 0, max: null, sqls: [ { - sql: 'node_memory_MemTotal_bytes{instance="{macIp}"}', + sql: 'avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="system"}[1m])) by (instance)', start: startTime, end: endTime, step: 15, - series_name: '总内存', + series_name: '系统cpu使用率', + }, + { + sql: 'avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="user"}[1m])) by (instance)', + start: startTime, + end: endTime, + step: 15, + series_name: '用户cpu使用率', + }, + { + sql: 'avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="idle"}[1m])) by (instance)', + start: startTime, + end: endTime, + step: 15, + series_name: '单核cpu空闲率', }, + { + sql: 'avg(irate(node_cpu_seconds_total{group="",instance="{macIp}",mode="iowait"}[1m])) by (instance)', + start: startTime, + end: endTime, + step: 15, + series_name: '磁盘io使用率', + }, + /* { + sql: 'irate(node_disk_io_time_seconds_total{group="",instance="{macIp}",}[1m])', + start: startTime, + end: endTime, + step: 15, + series_name: '', + }, */ ] } }, - ], - net_layout_option: [ { - x: 0, y: 0, w: 3, h: 2, i: '0', - static: false, display: false, title: '***chart', + x: 0, y: 9, w: 4, h: 3, i: '11', + static: false, display: true, title: '磁盘总空间', + query: { + type: 'table', range: false, isChart: false, interval: 5, + target: 'more_query', + sqls: [{ + sql: 'node_filesystem_size_bytes{group="",instance="{macIp}",fstype=~"ext4|xfs"}/10^9', + columnList: [ + { prop: "filesystem", label: '文件系统' }, + { prop: "zone", label: '分区' }, + { prop: "size", label: '空间大小(GB)' }, + ], + columnValue: [ + { prop: 'filesystem', value: 'item.metric.fstype', type: '' }, + { prop: 'zone', value: 'item.metric.mountpoint', type: '' }, + { prop: 'size', value: 'item.value[1]', type: 'float' } + ] + }] + } + }, + { + x: 4, y: 9, w: 4, h: 3, i: '12', + static: false, display: true, title: '各分区可用空间', + query: { + type: 'table', range: false, isChart: false, interval: 5, + target: 'more_query', + sqls: [{ + sql: 'node_filesystem_avail_bytes {group="",instance="{macIp}",fstype=~"ext4|xfs"}', + columnList: [ + { prop: "filesystem", label: '文件系统' }, + { prop: "zone", label: '分区' }, + { prop: "avail", label: '可用空间(GB)' }, + ], + columnValue: [ + { prop: 'filesystem', value: 'item.metric.fstype', type: '' }, + { prop: 'zone', value: 'item.metric.mountpoint', type: '' }, + { prop: 'avail', value: 'item.value[1]', type: 'byte', } + ] + }, + { + sql: '1-(node_filesystem_free_bytes{group="",instance="{macIp}",fstype=~"ext4|xfs"} / node_filesystem_size_bytes{group="",instance="{macIp}",fstype=~"ext4|xfs"})', + columnList: [ + { prop: "use", label: '使用率' }, + ], + columnValue: [ + { prop: 'use', value: 'item.value[1]', type: 'percent', } + ] + }] + } + }, + { + x: 0, y: 12, w: 4, h: 3, i: '13', + static: false, display: true, title: '磁盘读取容量', query: { type: 'line', range: true, isChart: true, - target: 'byte2GB_series', unit: 'GiB', float: 2, min: 0, max: null, + target: 'byte2KB_series', unit: 'kB/s', float: 2, min: 0, max: null, sqls: [ { - sql: 'node_memory_MemTotal_bytes{instance="{macIp}"}', + sql: 'rate(node_disk_read_bytes_total{group="",instance="{macIp}"}[1m])', start: startTime, end: endTime, step: 15, - series_name: '总内存', + series_name: '读取', + }, + + + ] + } + }, + { + x: 4, y: 12, w: 4, h: 3, i: '14', + static: false, display: true, title: '磁盘写入容量', + query: { + type: 'line', range: true, isChart: true, + target: 'byte2KB_series', unit: 'kB/s', float: 2, min: 0, max: null, + sqls: [ + { + sql: 'rate(node_disk_written_bytes_total{group="",instance="{macIp}"}[1m])', + start: startTime, + end: endTime, + step: 15, + series_name: '写入', + }, + + ] + } + }, + { + x: 0, y: 15, w: 8, h: 3, i: '15', + static: false, display: true, title: 'TCP连接情况', + query: { + type: 'line', range: true, isChart: true, + target: '', unit: '', float: 2, min: 0, max: null, + sqls: [ + { + sql: 'node_netstat_Tcp_CurrEstab{group="",instance="{macIp}"}', + start: startTime, + end: endTime, + step: 15, + series_name: 'ESTABLISHED', + }, + { + sql: 'node_sockstat_TCP_tw{group="",instance="{macIp}"}', + start: startTime, + end: endTime, + step: 15, + series_name: 'TCP_tw', + }, + { + sql: 'irate(node_netstat_Tcp_ActiveOpens{group="",instance="{macIp}"}[1m])', + start: startTime, + end: endTime, + step: 15, + series_name: 'ActiveOpens', + }, + { + sql: 'irate(node_netstat_Tcp_PassiveOpens{group="",instance="{macIp}"}[1m])', + start: startTime, + end: endTime, + step: 15, + series_name: 'PassiveOpens', + }, + { + sql: 'node_sockstat_TCP_alloc{group="",instance="{macIp}"}', + start: startTime, + end: endTime, + step: 15, + series_name: 'TCP_alloc', + }, + { + sql: 'node_sockstat_TCP_inuse{group="",instance="{macIp}"}', + start: startTime, + end: endTime, + step: 15, + series_name: 'TCP_inuse', }, ] } diff --git a/web/src/views/MyEcharts.vue b/web/src/views/echarts/MyEcharts.vue similarity index 74% rename from web/src/views/MyEcharts.vue rename to web/src/views/echarts/MyEcharts.vue index ff0488a..7ecf076 100644 --- a/web/src/views/MyEcharts.vue +++ b/web/src/views/echarts/MyEcharts.vue @@ -1,22 +1,29 @@ - \ No newline at end of file diff --git a/web/src/views/echarts/chartTable.vue b/web/src/views/echarts/chartTable.vue new file mode 100644 index 0000000..d34b722 --- /dev/null +++ b/web/src/views/echarts/chartTable.vue @@ -0,0 +1,54 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/index.ts b/web/src/views/echarts/index.ts similarity index 81% rename from web/src/views/index.ts rename to web/src/views/echarts/index.ts index 7a6aa33..f5eaa13 100644 --- a/web/src/views/index.ts +++ b/web/src/views/echarts/index.ts @@ -4,7 +4,7 @@ export let endTime = (new Date() as any) / 1000; // 过滤prometheus接口返回的数据 export const filterProm = (res: any) => { - if (res.data.status === 'success' && res.data.data.result.length > 0) { + if (res && res.data.status === 'success' && res.data.data.result.length > 0) { return res.data.data.result.length === 1 ? res.data.data.result[0] : res.data.data.result; } else { return []; @@ -15,6 +15,37 @@ export const deepClone = (res: any) => { return JSON.parse(JSON.stringify(res)) } +// 测试数组是否为空,为空返回[],不为空返回有值元素的 ogject[] +export const filterNonEmptyObjects = (arr:any[]) => { + return arr.reduce((acc, innerArr) => { + // 遍历内部数组中的每个元素 + if (!Array.isArray(innerArr)) { + acc.push(innerArr); + } else { + innerArr.forEach((item:any) => { + // 检查当前项是否是一个非空对象 + if (item && typeof item === 'object' && Object.keys(item).length > 0) { + // 如果是非空对象,则添加到累加器数组中 + acc.push(item); + } + }); + } + return acc; + }, []); // 初始累加器数组为空数组 +} + +// 给对象数组的每个元素嵌套数组 +export const nestedArray = (arr:any) => { + return arr.map((item:any) => { + if (Array.isArray(item)) { + return item; + } else { + return [item]; + } + }) +} + + // 处理字节类型数据 export const handle_byte = (value: string, float: number, unit: string) => { let value2unit: string = '0.00'; @@ -35,7 +66,7 @@ export const handle_byte = (value: string, float: number, unit: string) => { } // echart颜色表 -let e_colors = ['#4980c9', '#67e0e3', '#ef6874', '#4ab92e', '#E6A23C', '#74a465', '#e24d42', '#ba43a9']; +let e_colors = ['#2988f1', '#f8b238', '#b477f7', '#00c69e', '#ff79c2', '#40b85b', '#e24d42', '#ba43a9']; // 柱状图 export const bar_opt = { @@ -65,6 +96,7 @@ export const line_opt = { tooltip: { show: true, trigger: 'axis', + confine: true, transitionDuration: 0.4, backgroundColor: 'rgba(255,255,255,1)', extraCssText: 'min-height:130px;', diff --git a/web/src/views/nodeDetail.vue b/web/src/views/nodeDetail.vue index 80eeef5..45cd732 100644 --- a/web/src/views/nodeDetail.vue +++ b/web/src/views/nodeDetail.vue @@ -1,7 +1,7 @@