Skip to content

Commit

Permalink
refactor: kms monitoring statistical data
Browse files Browse the repository at this point in the history
  • Loading branch information
ikxin committed Aug 21, 2024
1 parent 814b5a2 commit 07c6815
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 121 deletions.
2 changes: 1 addition & 1 deletion service/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const runCheck = async () => {
success,
fail,
delay: Number(delay),
rate: Number((success / total).toFixed(2)),
rate: Number((success / total).toFixed(4)),
updatedAt: new Date(),
})
.where(eq(schema.server.host, host))
Expand Down
4 changes: 2 additions & 2 deletions service/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export type RunVlmcsParams = {
export interface RunVlmcsParams {
host: string
port?: number
app?: number
protocol?: number
}

export type RunVlmcsResult = {
export interface RunVlmcsResult {
host: string
content: string
delay: number
Expand Down
45 changes: 10 additions & 35 deletions src/store/monitor.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
import axios from 'axios'
import dayjs from 'dayjs'
import { Notification } from '@arco-design/web-vue'
import fetch from '@/utils/fetch'

export const useMonitorStore = defineStore('monitor', () => {
const apiUrl = 'https://api.uptimerobot.com/v2/getMonitors'
const apiKey = ['m794366630-4128d6474ac33847941241ec', 'm790633514-8e1d658a806daa670799a6f5']

const timestamps = Array.from({ length: 120 }, (_, num) => {
return (
dayjs().startOf('day').subtract(num, 'day').unix() +
'_' +
dayjs().startOf('day').subtract(num, 'day').endOf('day').unix()
)
}).reverse()

const loading = ref(false)
const monitors = useStorage('monitors', [])

const getMonitors = async () => {
loading.value = true
const _monitors = []
if (monitors.value.length !== 0) {
loading.value = false
return
}
for (const api_key of apiKey) {
try {
const { data } = await axios.post(apiUrl, {
api_key,
custom_uptime_ranges: timestamps.join('-'),
})
_monitors.push(...data.monitors)
} catch ({ code, message }) {
Notification.error({ title: code, content: message })
loading.value = false
}
try {
const { data } = await fetch('/api/server')
data.sort((prev: { rate: number }, next: { rate: number }) => {
return next.rate - prev.rate
})
monitors.value = data
} catch (err) {
console.log(err)
}
monitors.value = _monitors
loading.value = false
}

return { getMonitors, loading, monitors }
return { getMonitors, monitors }
})
7 changes: 1 addition & 6 deletions src/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ body {
}

#app {
@apply flex flex-col gap-4 min-h-screen bg-[--color-neutral-2] text-[--color-text-2];
@apply flex flex-col gap-4 min-h-screen bg-[--color-neutral-2] text-[--color-text-2] select-none;
}

.arco-layout-header span > i {
font-size: 1rem;
}

.arco-dropdown{
@apply select-none;
}

16 changes: 16 additions & 0 deletions src/utils/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import axios, { AxiosResponse } from 'axios'
import { Notification } from '@arco-design/web-vue'

const fetch = axios.create({
baseURL: import.meta.env.VITE_BASE_URL || 'https://kms.ikxin.com',
timeout: 10 * 1000,
})

fetch.interceptors.response.use(
(res: AxiosResponse) => res,
(err: Error) => {
Notification.error({ title: 'Error', content: String(err).trim() })
},
)

export default fetch
113 changes: 62 additions & 51 deletions src/views/monitor.vue
Original file line number Diff line number Diff line change
@@ -1,69 +1,80 @@
<script setup lang="ts">
import { useMonitorStore } from '@/store/monitor'
import { TableColumnData } from '@arco-design/web-vue'
import dayjs from 'dayjs'
import * as echarts from 'echarts'
const columns = [
const columns: TableColumnData[] = [
{
dataIndex: 'friendly_name',
title: 'Domain',
width: 160,
dataIndex: 'host',
title: '服务器',
minWidth: 160,
},
{
dataIndex: 'custom_uptime_ranges',
title: 'Uptime Ranges',
dataIndex: 'port',
title: '端口',
width: 80,
},
{
dataIndex: 'rate',
title: '成功率',
width: 100,
align: 'center',
sortable: {
sortDirections: ['ascend', 'descend'],
},
render({ record }) {
return h('div', { id: record.id, class: 'h-36' })
return `${(record.rate * 100).toFixed(2)} %`
},
},
{
dataIndex: 'delay',
title: '平均延迟',
width: 120,
align: 'center',
sortable: {
sortDirections: ['ascend', 'descend'],
},
render({ record }) {
return `${record.delay.toFixed(2)} ms`
},
},
{
dataIndex: 'total',
title: '总请求',
width: 80,
align: 'center',
},
{
dataIndex: 'success',
title: '成功数',
width: 80,
align: 'center',
},
{
dataIndex: 'fail',
title: '失败数',
width: 80,
align: 'center',
},
{
dataIndex: 'updatedAt',
title: '更新时间',
width: 170,
render({ record }) {
return dayjs(record.updatedAt).format('YYYY-MM-DD HH:mm:ss')
},
},
]
const monitorStore = useMonitorStore()
onMounted(() => {
monitorStore.monitors.forEach(item => {
const ranges = Array.from({ length: 120 }, (_, num) => {
return dayjs().subtract(num, 'day').format('YYYY-MM-DD')
}).reverse()
const uptime = item.custom_uptime_ranges.split('-')
const customUptimeRanges = ranges.map((item, index) => [item, Number(uptime[index])])
const echart = echarts.init(document.getElementById(item.id), null, { locale: 'EN' })
echart.setOption({
tooltip: {},
visualMap: {
align: 'left',
min: 0,
max: 100,
type: 'piecewise',
left: 'right',
top: 'center',
inRange: {
color: ['#ebedf0', '#f44336', '#ffc107', '#41c464'],
symbolSize: [0, 99, 100],
},
},
calendar: {
cellSize: [32, 16],
itemStyle: { borderWidth: 0.5 },
top: 'center',
left: 20,
range: [ranges.at(0), ranges.at(-1)],
yearLabel: { show: false },
},
series: {
type: 'heatmap',
coordinateSystem: 'calendar',
data: customUptimeRanges,
},
})
})
})
</script>

<template>
<ASpin :loading="monitorStore.loading" dot>
<ATable :columns="columns" :data="monitorStore.monitors"></ATable>
<ASpin :loading="false" dot>
<ATable
:columns="columns"
:data="monitorStore.monitors"
:pagination="false"
></ATable>
</ASpin>
</template>
42 changes: 24 additions & 18 deletions src/views/tools.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { FieldRule, Notification } from '@arco-design/web-vue'
import { appItems } from '@/assets/items/check'
import { useAxios } from '@vueuse/integrations/useAxios'
import fetch from '@/utils/fetch'
import { FieldRule, ValidatedError } from '@arco-design/web-vue'
const { t } = useI18n()
Expand Down Expand Up @@ -45,21 +45,24 @@ const resultInfo = reactive<{
visible: false,
})
const handleSubmit = async data => {
const handleSubmit = async (data: {
values: Record<string, any>
errors: Record<string, ValidatedError> | undefined
}) => {
if (data.errors === undefined) {
resultInfo.loading = true
try {
const { data } = await useAxios('/api/check', {
const { data } = await fetch({
url: '/api/check',
method: 'post',
data: formData.value,
headers: { 'Content-Type': 'multipart/form-data' },
})
resultInfo.message = data.value.content
resultInfo.type = data.value.status ? 'success' : 'error'
resultInfo.message = data.content
resultInfo.type = data.status ? 'success' : 'error'
resultInfo.visible = true
resultInfo.loading = false
} catch ({ code, message }) {
Notification.error({ title: code, content: message })
} catch (err) {
resultInfo.loading = false
}
}
Expand All @@ -86,24 +89,27 @@ const handleSubmit = async data => {
<AFormItem :label="t('label.port')" field="port">
<AInput v-model="formData.port"></AInput>
</AFormItem>
<AFormItem :label="t('label.software')" field="software">
<ASelect v-model="formData.software">
<AOption
v-for="(value, key) in appItems"
:key="key"
:value="key"
:label="value"
/>
</ASelect>
</AFormItem>
<AFormItem :label="t('label.protocol')" field="protocol">
<ASelect v-model="formData.protocol">
<AOption value="6">V6 Protocol</AOption>
<AOption value="5">V5 Protocol</AOption>
<AOption value="4">V4 Protocol</AOption>
</ASelect>
</AFormItem>
<AFormItem :label="t('label.software')" field="software">
<ASelect v-model="formData.software">
<AOption v-for="(value, key) in appItems" :key="key" :value="key">{{
value
}}</AOption>
</ASelect>
</AFormItem>
<AFormItem>
<AButton html-type="submit" type="primary">{{
t('button.submit')
}}</AButton>
<AButton html-type="submit" type="primary">
{{ t('button.submit') }}
</AButton>
</AFormItem>
</AForm>
<AAlert
Expand Down
8 changes: 0 additions & 8 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,4 @@ export default defineConfig({
'@': resolve(__dirname, './src'),
},
},
server: {
proxy: {
'/api': {
target: 'https://kmstools.ikxin.com/',
changeOrigin: true,
},
},
},
})

0 comments on commit 07c6815

Please sign in to comment.