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