|
|
@ -6,185 +6,82 @@
|
|
|
|
-->
|
|
|
|
-->
|
|
|
|
<template>
|
|
|
|
<template>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<div v-if="id">
|
|
|
|
<div class="page-h1">
|
|
|
|
<div class="text-2xl mb-4">
|
|
|
|
服务
|
|
|
|
消息服务
|
|
|
|
|
|
|
|
<div class="float-right text-sm">{{ new Date(data.now).toLocaleString() }}</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="">
|
|
|
|
<q-card class="w-40 text-center py-4 start_card">
|
|
|
|
<div class="w-full">ID: {{ id }}</div>
|
|
|
|
<div class="text-3xl"> 已运行 </div>
|
|
|
|
<div class="flex gap-8">
|
|
|
|
<div class="text-2xl mt-2">
|
|
|
|
<div>CPU占用: {{ data.cpu }}%</div>
|
|
|
|
{{ start_time }}
|
|
|
|
<div>内存占用: {{ (data.mem / 1024 / 1024).toFixed(2) }}M</div>
|
|
|
|
|
|
|
|
<div>连接数: {{ data.connections }}</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div>发送: {{ (send_received[0] / 1024).toFixed(2) }} KB/s</div>
|
|
|
|
</q-card>
|
|
|
|
<div>收到: {{ (send_received[1] / 1024).toFixed(2) }} KB/s</div>
|
|
|
|
<div class="flex flex-nowrap" style="">
|
|
|
|
|
|
|
|
<div class="w-1/2">
|
|
|
|
|
|
|
|
<tschart :item="querys[0]" :time_mode="1"></tschart>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="grid grid-cols-4 gap-4 mt-10" v-if="conns.length">
|
|
|
|
<div class="w-1/2">
|
|
|
|
<div>ID</div>
|
|
|
|
<tschart :item="querys[1]" :time_mode="1"></tschart>
|
|
|
|
<div>Name</div>
|
|
|
|
|
|
|
|
<div>运行时间</div>
|
|
|
|
|
|
|
|
<div>订阅主题</div>
|
|
|
|
|
|
|
|
<template v-for="c of conns" :key="c.cid">
|
|
|
|
|
|
|
|
<div>{{ c.cid }}</div>
|
|
|
|
|
|
|
|
<div>{{ c.name || '无' }}</div>
|
|
|
|
|
|
|
|
<div>{{ new Date(c.start).toLocaleString() }}</div>
|
|
|
|
|
|
|
|
<div>{{ c.subscriptions_list ?
|
|
|
|
|
|
|
|
c.subscriptions_list.sort().join(' ') : '' }}</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="flex flex-nowrap">
|
|
|
|
|
|
|
|
<div class="grow" style="min-height: 50vh;">
|
|
|
|
|
|
|
|
<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>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { computed, ref, watch, onUnmounted } from 'vue';
|
|
|
|
import { ref, onUnmounted, onMounted } from 'vue';
|
|
|
|
import { nats } from '@veypi/oaer'
|
|
|
|
|
|
|
|
import api from 'src/boot/api'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const data = ref({} as any)
|
|
|
|
|
|
|
|
const conns = ref<any[]>([])
|
|
|
|
|
|
|
|
const id = computed(() => data.value.server_id)
|
|
|
|
|
|
|
|
const subs: any[] = []
|
|
|
|
|
|
|
|
const timer = ref()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let old_data = [0, 0]
|
|
|
|
|
|
|
|
const send_received = computed(() => {
|
|
|
|
|
|
|
|
if (!id.value) {
|
|
|
|
|
|
|
|
return [0, 0]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let os = data.value.out_bytes
|
|
|
|
|
|
|
|
let or = data.value.in_bytes
|
|
|
|
|
|
|
|
let res = [os - old_data[0], or - old_data[1]]
|
|
|
|
|
|
|
|
old_data = [os, or]
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(id, (_) => {
|
|
|
|
|
|
|
|
timer.value = setInterval(() => {
|
|
|
|
|
|
|
|
api.nats.general().then(e => {
|
|
|
|
|
|
|
|
data.value = e
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
api.nats.conns().then(e => {
|
|
|
|
|
|
|
|
conns.value = e.connections
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
// nats.request('$SYS.REQ.SERVER.PING').then((m) => {
|
|
|
|
|
|
|
|
// data.value = JSON.parse(m)
|
|
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(computed(() => nats.ready.value), e => {
|
|
|
|
|
|
|
|
if (e) {
|
|
|
|
|
|
|
|
api.nats.general().then(e => {
|
|
|
|
|
|
|
|
old_data = [e.out_bytes, e.in_bytes]
|
|
|
|
|
|
|
|
data.value = e
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, { immediate: true })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
|
|
if (timer.value) {
|
|
|
|
|
|
|
|
clearInterval(timer.value)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i of subs) {
|
|
|
|
|
|
|
|
i.unsubscribe()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
import tschart from 'src/components/tschart';
|
|
|
|
import tschart from 'src/components/tschart';
|
|
|
|
|
|
|
|
import api from 'src/boot/api';
|
|
|
|
|
|
|
|
|
|
|
|
const idx = ref(0)
|
|
|
|
const start_time = ref('')
|
|
|
|
|
|
|
|
const timer = ref()
|
|
|
|
const querys = ref<{
|
|
|
|
const querys = ref<{
|
|
|
|
name: string, query: string[] | string, label?: any,
|
|
|
|
name: string, query: string[] | string, label?: any,
|
|
|
|
valueFormatter?: any
|
|
|
|
valueFormatter?: any
|
|
|
|
}[]>([
|
|
|
|
}[]>([
|
|
|
|
{
|
|
|
|
{
|
|
|
|
name: 'cpu占用',
|
|
|
|
name: 'cpu',
|
|
|
|
// query: `100 - avg (irate(node_cpu_seconds_total{mode="idle"}[3s]))
|
|
|
|
query: `oa_stats_cpu`,
|
|
|
|
// by(id) * 100`,
|
|
|
|
label: 'cpu',
|
|
|
|
query: `avg by
|
|
|
|
|
|
|
|
(id)(irate(node_cpu_seconds_total{mode=~"sytem|user|iowait|irq|softirq|nice|steal|guest"}[3s]))
|
|
|
|
|
|
|
|
* 100`,
|
|
|
|
|
|
|
|
label: (d: any) => d.id as string,
|
|
|
|
|
|
|
|
valueFormatter: (value: number) => value.toFixed(2) + "%",
|
|
|
|
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: '磁盘',
|
|
|
|
|
|
|
|
query: `(1 - avg(node_filesystem_avail_bytes /
|
|
|
|
|
|
|
|
node_filesystem_size_bytes[3s]) by (device, id)) * 100 `,
|
|
|
|
|
|
|
|
label: (d: any) => `${d.id}: ${d.device}` as string,
|
|
|
|
|
|
|
|
valueFormatter: (value: number) => value.toFixed(2) + "%",
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: '磁盘IOPS',
|
|
|
|
|
|
|
|
query: [
|
|
|
|
|
|
|
|
`sum by (id) (rate(node_disk_reads_completed_total[3s]))`,
|
|
|
|
|
|
|
|
`sum by (id) (rate(node_disk_writes_completed_total[3s]))`,
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
label: [
|
|
|
|
|
|
|
|
(d: any) => `${d.id} 读`,
|
|
|
|
|
|
|
|
(d: any) => `${d.id} 写`,
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: '网络带宽',
|
|
|
|
|
|
|
|
query: [
|
|
|
|
|
|
|
|
`sum by(id)(irate(node_network_receive_bytes_total{device!~"bond.*?|lo"}[3s])) / 1048576`,
|
|
|
|
|
|
|
|
`sum by(id)(irate(node_network_transmit_bytes_total{device!~"bond.*?|lo"}[3s])) / 1048576`
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
label: [
|
|
|
|
|
|
|
|
(d: any) => `${d.id} 下行`,
|
|
|
|
|
|
|
|
(d: any) => `${d.id} 上行`,
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
valueFormatter: (value: number) => value.toFixed(2) + "MB/s",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
name: '内存',
|
|
|
|
name: '内存',
|
|
|
|
query: [
|
|
|
|
query: `oa_stats_mem / 1048576`,
|
|
|
|
`(node_memory_Buffers_bytes + node_memory_Cached_bytes +
|
|
|
|
label: '内存',
|
|
|
|
node_memory_MemFree_bytes) / 1024 / 1024 / 1024`,
|
|
|
|
valueFormatter: (value: number) => value.toFixed(2) + "MB",
|
|
|
|
`node_memory_MemTotal_bytes / 1024 /1024 / 1024`
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
label: [(d: any) => `${d.id}使用内`, (d: any) => `${d.id}总内存`],
|
|
|
|
|
|
|
|
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 '
|
|
|
|
|
|
|
|
// },
|
|
|
|
|
|
|
|
])
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
|
|
api.tsdb.query('oa_stats_start').then(e => {
|
|
|
|
|
|
|
|
if (e.data.result.length) {
|
|
|
|
|
|
|
|
let s = Number(e.data.result[0].value[1])
|
|
|
|
|
|
|
|
if (s < 60) {
|
|
|
|
|
|
|
|
start_time.value = s + ' 秒'
|
|
|
|
|
|
|
|
} else if (s < 3600) {
|
|
|
|
|
|
|
|
start_time.value = (s / 60).toFixed(1) + ' 分钟'
|
|
|
|
|
|
|
|
} else if (s < 3600 * 24) {
|
|
|
|
|
|
|
|
start_time.value = (s / 60 / 60).toFixed(1) + ' 小时'
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
start_time.value = (s / 60 / 60 / 24).toFixed(1) + ' 天'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
|
|
if (timer.value) {
|
|
|
|
|
|
|
|
clearInterval(timer.value)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped></style>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
|
|
.start_card {
|
|
|
|
|
|
|
|
:first-child {
|
|
|
|
|
|
|
|
color: $primary
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:nth-child(2) {}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|