feat: 添加缓存监控
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { http } from "@/utils/http";
|
||||
import type {
|
||||
OperationLogInfo,
|
||||
RedisMonitorInfo,
|
||||
SystemMonitorInfo,
|
||||
UserLoginLogInfo
|
||||
} from "types/monitor";
|
||||
@@ -59,3 +60,13 @@ export const getUserOperationsAPI = (params: {
|
||||
export const getSystemMonitorInfoAPI = () => {
|
||||
return http.request<SystemMonitorInfo>("get", "/api/server");
|
||||
};
|
||||
|
||||
// --------------------------缓存相关--------------------------------------
|
||||
|
||||
/**
|
||||
* 获取服务器缓存信息
|
||||
* @returns
|
||||
*/
|
||||
export const getCachedMonitorInfoAPI = () => {
|
||||
return http.request<RedisMonitorInfo>("get", "/api/cache/monitor");
|
||||
};
|
||||
|
||||
279
src/views/monitor/cache/index.vue
vendored
Normal file
279
src/views/monitor/cache/index.vue
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<el-row>
|
||||
<re-col :value="24" :xs="24" :sm="24">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-center">
|
||||
<IconifyIconOffline :icon="Monitor" />
|
||||
<span class="header-title">基本信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions :column="4" border class="centered-descriptions">
|
||||
<el-descriptions-item align="center" label="Redis版本" :span="1">
|
||||
{{ cache.info?.redis_version || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="运行模式" :span="1">
|
||||
{{ cache.info?.redis_mode === "standalone" ? "单机" : "集群" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="端口" :span="1">
|
||||
{{ cache.info?.tcp_port || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="客户端数" :span="1">
|
||||
{{ cache.info?.connected_clients || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="运行时间(天)" :span="1">
|
||||
{{ cache.info?.uptime_in_days || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="使用内存" :span="1">
|
||||
{{ cache.info?.used_memory_human || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="使用CPU" :span="1">
|
||||
{{
|
||||
cache.info?.used_cpu_user_children !== undefined
|
||||
? parseFloat(cache.info.used_cpu_user_children).toFixed(2)
|
||||
: "-"
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="内存配置" :span="1">
|
||||
{{ cache.info?.maxmemory_human || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="AOF是否开启" :span="1">
|
||||
{{ cache.info?.aof_enabled === "0" ? "否" : "是" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="RDB是否成功" :span="1">
|
||||
{{ cache.info?.rdb_last_bgsave_status || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="Key数量" :span="1">
|
||||
{{ cache.dbSize || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item
|
||||
align="center"
|
||||
label="网络入口/出口"
|
||||
:span="1"
|
||||
>
|
||||
{{
|
||||
cache.info
|
||||
? `${cache.info.instantaneous_input_kbps}kps/${cache.info.instantaneous_output_kbps}kps`
|
||||
: "-"
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="内存使用率" :span="1">
|
||||
{{
|
||||
cache.info?.used_memory !== undefined &&
|
||||
cache.info?.maxmemory !== undefined &&
|
||||
cache.info.maxmemory > 0
|
||||
? (
|
||||
(cache.info.used_memory / cache.info.maxmemory) *
|
||||
100
|
||||
).toFixed(2) + "%"
|
||||
: "-"
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="操作系统" :span="1">
|
||||
{{ cache.info?.os || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="架构位数" :span="1">
|
||||
{{ cache.info?.arch_bits || "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item align="center" label="多路复用API" :span="1">
|
||||
{{ cache.info?.multiplexing_api || "-" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col :value="12" :xs="24" :sm="24">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-center">
|
||||
<IconifyIconOffline :icon="PieChart" />
|
||||
<span class="header-title">命令统计</span>
|
||||
</div>
|
||||
</template>
|
||||
<div ref="commandstats" style="height: 420px" />
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col :value="12" :xs="24" :sm="24">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-center">
|
||||
<IconifyIconOffline :icon="Odometer" />
|
||||
<span class="header-title">内存信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<div ref="usedmemory" style="height: 420px" />
|
||||
</el-card>
|
||||
</re-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "MonitorCache"
|
||||
});
|
||||
import ReCol from "@/components/ReCol";
|
||||
import { ref, onMounted, nextTick, reactive } from "vue";
|
||||
import { getCachedMonitorInfoAPI } from "@/api/monitor";
|
||||
import * as echarts from "echarts";
|
||||
import Monitor from "@iconify-icons/ep/monitor";
|
||||
import PieChart from "@iconify-icons/ep/pie-chart";
|
||||
import Odometer from "@iconify-icons/ep/odometer";
|
||||
|
||||
const cache = reactive({
|
||||
commandStats: [] as { name: string; value: number }[],
|
||||
dbSize: 0,
|
||||
info: {
|
||||
redis_version: "",
|
||||
redis_mode: "",
|
||||
tcp_port: 0,
|
||||
connected_clients: 0,
|
||||
uptime_in_days: 0,
|
||||
used_memory_human: "",
|
||||
used_cpu_user_children: "",
|
||||
maxmemory_human: "",
|
||||
aof_enabled: "",
|
||||
rdb_last_bgsave_status: "",
|
||||
instantaneous_input_kbps: 0,
|
||||
instantaneous_output_kbps: 0,
|
||||
used_memory: 0,
|
||||
maxmemory: 0,
|
||||
os: "",
|
||||
arch_bits: 0,
|
||||
multiplexing_api: ""
|
||||
}
|
||||
});
|
||||
|
||||
const commandstats = ref(null);
|
||||
const usedmemory = ref(null);
|
||||
|
||||
const getCacheInfo = async () => {
|
||||
const res = await getCachedMonitorInfoAPI();
|
||||
if (res.success) {
|
||||
Object.assign(cache, res.data);
|
||||
|
||||
nextTick(() => {
|
||||
initCommandStatsChart();
|
||||
initUsedMemoryChart();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const initCommandStatsChart = () => {
|
||||
const chart = echarts.init(commandstats.value);
|
||||
const commandData = cache.commandStats || [];
|
||||
const seriesData = commandData.map((cmd: any) => ({
|
||||
name: cmd.name,
|
||||
value: parseInt(cmd.value, 10)
|
||||
}));
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: "命令统计",
|
||||
left: "center"
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b}: {c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
left: "left"
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "命令",
|
||||
type: "pie",
|
||||
radius: "50%",
|
||||
data: seriesData,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: "rgba(0, 0, 0, 0.5)"
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
formatter: "{b}: {c} ({d}%)"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chart.setOption(option);
|
||||
};
|
||||
|
||||
const initUsedMemoryChart = () => {
|
||||
const chart = echarts.init(usedmemory.value);
|
||||
const usedMemory = cache.info?.used_memory || 0;
|
||||
const maxMemory = cache.info?.maxmemory || 0;
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: "内存信息",
|
||||
left: "center"
|
||||
},
|
||||
tooltip: {
|
||||
formatter: "{b} <br/>{a} : " + cache.info.used_memory_human
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "峰值",
|
||||
type: "gauge",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
detail: {
|
||||
formatter: cache.info.used_memory_human
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: parseFloat(cache.info.used_memory_human),
|
||||
name: "内存消耗"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chart.setOption(option);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getCacheInfo();
|
||||
setInterval(() => {
|
||||
getCacheInfo();
|
||||
}, 60000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
margin-left: 0.5em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.centered-descriptions {
|
||||
:deep(.el-descriptions-item__container) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions-item__label) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions-item__content) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user