mirror of https://github.com/veypi/OneAuth.git
system info collect and show
parent
bb49108a5f
commit
583bca4817
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* tsdb.ts
|
||||||
|
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
* 2023-10-20 23:21
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import ajax from './axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
local: './ts/',
|
||||||
|
range(query: string, props?: { start?: string, end?: string, step?: string, query?: string }) {
|
||||||
|
if (query !== undefined) {
|
||||||
|
// @ts-ignore
|
||||||
|
props.query = query
|
||||||
|
} else {
|
||||||
|
props = { query: query }
|
||||||
|
}
|
||||||
|
return ajax.get(this.local + 'query_range', props)
|
||||||
|
},
|
||||||
|
query(query: string) {
|
||||||
|
return ajax.get(this.local + 'query', { query: query })
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
<!--
|
||||||
|
* tschart.vue
|
||||||
|
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
* 2023-10-20 22:50
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="w-full h-full">
|
||||||
|
<div class="v-chart w-full h-full" ref="chartdom"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import * as echart from 'echarts'
|
||||||
|
import api from 'src/boot/api';
|
||||||
|
import { onMounted, onUnmounted, computed, ref, watch, markRaw } from 'vue';
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
name: string
|
||||||
|
query: string | string[]
|
||||||
|
ext?: string
|
||||||
|
valueFormatter?: (s: number) => string
|
||||||
|
label?: string | string[] | ((s: any) => string)
|
||||||
|
}
|
||||||
|
let props = withDefaults(defineProps<{
|
||||||
|
item: Item,
|
||||||
|
// start?: string,
|
||||||
|
// end?: string,
|
||||||
|
// step?: string
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
}
|
||||||
|
)
|
||||||
|
let getparams = ref<any>({
|
||||||
|
start: () => {
|
||||||
|
let d = new Date()
|
||||||
|
d.setMinutes(d.getMinutes() - 3)
|
||||||
|
return d.toISOString()
|
||||||
|
}, end: undefined, step: '2s'
|
||||||
|
})
|
||||||
|
let count = 0
|
||||||
|
let timer = ref<any[]>([])
|
||||||
|
let chartdom = ref()
|
||||||
|
let options = ref<{ [key: string]: any }>({})
|
||||||
|
let chart: echart.ECharts = {} as any
|
||||||
|
let tooltip = {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {},
|
||||||
|
},
|
||||||
|
valueFormatter: (value: number) => value.toFixed(2),
|
||||||
|
className: 'v-echarts-tooltip',
|
||||||
|
}
|
||||||
|
|
||||||
|
const init_chart = () => {
|
||||||
|
count++
|
||||||
|
if (chart.clear) {
|
||||||
|
chart.clear()
|
||||||
|
}
|
||||||
|
options.value = {
|
||||||
|
animationThreshold: 200,
|
||||||
|
tooltip: Object.assign({}, tooltip),
|
||||||
|
axisPointer: {
|
||||||
|
link: { xAxisIndex: 'all' },
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#777'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
},
|
||||||
|
yAxis: {},
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
if (props.item.valueFormatter) {
|
||||||
|
options.value.tooltip.valueFormatter = props.item.valueFormatter
|
||||||
|
}
|
||||||
|
let tmp = {} as any
|
||||||
|
if (getparams.value.start) {
|
||||||
|
tmp.start = getparams.value.start()
|
||||||
|
}
|
||||||
|
if (getparams.value.step) {
|
||||||
|
tmp.step = getparams.value.step
|
||||||
|
}
|
||||||
|
let query: string[] = Array.isArray(props.item.query) ? props.item.query :
|
||||||
|
[props.item.query]
|
||||||
|
for (let q = 0; q < query.length; q++) {
|
||||||
|
api.tsdb.range(query[q], tmp).then(e => {
|
||||||
|
if (e.status == 'success') {
|
||||||
|
let data = e.data.result as any[]
|
||||||
|
if (data.length == 0) {
|
||||||
|
console.warn('not get data')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let idx = options.value.series.length || 0
|
||||||
|
data.forEach(d => {
|
||||||
|
let name = props.item.name
|
||||||
|
if (typeof props.item.label === 'string') {
|
||||||
|
name = props.item.label
|
||||||
|
} else if (typeof props.item.label === 'function') {
|
||||||
|
name = props.item.label(d.metric)
|
||||||
|
} else if (Array.isArray(props.item.label)) {
|
||||||
|
name = props.item.label[q]
|
||||||
|
}
|
||||||
|
options.value.series.push({
|
||||||
|
name: name,
|
||||||
|
data: d.values.map((e: any) =>
|
||||||
|
[e[0] * 1000, Number(e[1])]),
|
||||||
|
metric: d.metric,
|
||||||
|
origin: query[q],
|
||||||
|
symbol: 'none',
|
||||||
|
smooth: true,
|
||||||
|
type: 'line',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
chart.setOption(options.value)
|
||||||
|
let t = setInterval(() => {
|
||||||
|
sync_chart(idx, query[q], count)
|
||||||
|
}, 1000)
|
||||||
|
timer.value.push(t)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// let query = props.query
|
||||||
|
}
|
||||||
|
const sync_chart = (idx: number, query: string, c: number) => {
|
||||||
|
api.tsdb.query(query).then(e => {
|
||||||
|
if (e.status == 'success') {
|
||||||
|
let data = e.data.result as any[]
|
||||||
|
if (data.length == 0) {
|
||||||
|
console.warn('not get data')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (count === c) {
|
||||||
|
data.forEach((d, i) => {
|
||||||
|
options.value.series[idx + i].data.push([d.value[0] * 1000,
|
||||||
|
Number(d.value[1])])
|
||||||
|
})
|
||||||
|
chart.setOption(options.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(computed(() => props.item), q => {
|
||||||
|
timer.value.forEach(e => {
|
||||||
|
clearInterval(e)
|
||||||
|
})
|
||||||
|
if (q) {
|
||||||
|
init_chart()
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
chart = markRaw(echart.init(chartdom.value))
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
timer.value.forEach(e => {
|
||||||
|
clearInterval(e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.v-chart {}
|
||||||
|
|
||||||
|
.v-echarts-tooltip {
|
||||||
|
/* height: 5rem; */
|
||||||
|
/* width: 10rem; */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,69 @@
|
|||||||
|
<!--
|
||||||
|
* stats.vue
|
||||||
|
* Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
* 2023-10-20 22:56
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-nowrap">
|
||||||
|
<div class="grow" style="height: calc(100%);">
|
||||||
|
<tschart :item="querys[idx]"></tschart>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-5">
|
||||||
|
<q-chip :color="idx === i ? 'primary' : ''" class="select-none" v-for="(q, i) in querys" :key="i" @click="idx = i"
|
||||||
|
clickable>{{
|
||||||
|
q.name }} </q-chip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import tschart from 'src/components/tschart.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const idx = ref(0)
|
||||||
|
const querys = ref([
|
||||||
|
{
|
||||||
|
name: 'cpu占用',
|
||||||
|
query: `100 - avg (irate(node_cpu_seconds_total{mode="idle"}[3s]))
|
||||||
|
by(id) * 100`,
|
||||||
|
label: (d: any) => d.id as string,
|
||||||
|
valueFormatter: (value: number) => value.toFixed(2) + "%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'linux内存使用率',
|
||||||
|
query: [
|
||||||
|
`((node_memory_Buffers_bytes + node_memory_Cached_bytes +
|
||||||
|
node_memory_MemFree_bytes) / node_memory_MemTotal_bytes) * 100`,
|
||||||
|
],
|
||||||
|
label: (d: any) => d.id as string,
|
||||||
|
valueFormatter: (value: number) => value.toFixed(2) + "%",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'linux 内存',
|
||||||
|
query: [
|
||||||
|
`(node_memory_Buffers_bytes + node_memory_Cached_bytes +
|
||||||
|
node_memory_MemFree_bytes) / 1024 / 1024 / 1024`,
|
||||||
|
`node_memory_MemTotal_bytes / 1024 /1024 / 1024`
|
||||||
|
],
|
||||||
|
label: ['使用内存', '总内存'],
|
||||||
|
valueFormatter: (value: number) => value.toFixed(2) + "GB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mac cpu频率',
|
||||||
|
query: 'node_cpu_seconds_total',
|
||||||
|
label: (d: any) => `cpu: ${d.cpu} mode: ${d.mode}` as string
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mem',
|
||||||
|
query: 'node_memory_free_bytes / 1024 / 1024 / 1024'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mac swap',
|
||||||
|
query: 'node_memory_swap_used_bytes / 1024 / 1024 '
|
||||||
|
},
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue