Update redis and server monitor implementations (#1000)

* Update redis and server monitor implementations

* Fix server disk information
This commit is contained in:
Wu Clan
2026-01-11 13:21:37 +08:00
committed by GitHub
parent dfce2ca094
commit 28a6228556
6 changed files with 277 additions and 238 deletions
+31 -7
View File
@@ -1,16 +1,40 @@
from fastapi import APIRouter
from backend.common.response.response_schema import ResponseModel, response_base
from backend.app.admin.schema.monitor import RedisCommandStat, RedisMonitorInfo, RedisServerInfo
from backend.common.response.response_schema import ResponseSchemaModel, response_base
from backend.common.security.jwt import DependsJwtAuth
from backend.utils.redis_info import redis_info
from backend.database.redis import redis_client
from backend.utils.format import fmt_seconds
router = APIRouter()
@router.get('', summary='redis 监控', dependencies=[DependsJwtAuth])
async def get_redis_info() -> ResponseModel:
data = {
'info': await redis_info.get_info(),
'stats': await redis_info.get_stats(),
}
async def get_redis_info() -> ResponseSchemaModel[RedisMonitorInfo]:
info = await redis_client.info()
db_size = await redis_client.dbsize()
uptime_formatted = fmt_seconds(int(info.get('uptime_in_seconds', 0)))
server_info = RedisServerInfo(
redis_version=str(info.get('redis_version', '')),
redis_mode=str(info.get('redis_mode', '')),
os=str(info.get('os', '')),
arch_bits=str(info.get('arch_bits', '')),
tcp_port=str(info.get('tcp_port', '')),
uptime_in_seconds=uptime_formatted,
connected_clients=str(info.get('connected_clients', '')),
used_memory_human=str(info.get('used_memory_human', '')),
used_memory_peak_human=str(info.get('used_memory_peak_human', '')),
maxmemory_human=str(info.get('maxmemory_human', '0B')),
keys_num=str(db_size),
)
command_stats = await redis_client.info('commandstats')
stats_list = []
for key, value in command_stats.items():
if isinstance(value, dict):
stats_list.append(RedisCommandStat(name=key.split('_')[-1], value=str(value.get('calls', '0'))))
data = RedisMonitorInfo(info=server_info, stats=stats_list)
return response_base.success(data=data)
+124 -11
View File
@@ -1,21 +1,134 @@
import os
import platform
import socket
import sys
from datetime import datetime
from datetime import timezone as tz
import psutil
from fastapi import APIRouter
from starlette.concurrency import run_in_threadpool
from backend.common.response.response_schema import ResponseModel, response_base
from backend.app.admin.schema.monitor import (
CpuInfo,
DiskInfo,
MemInfo,
ServerMonitorInfo,
ServiceInfo,
SysInfo,
)
from backend.common.response.response_schema import ResponseSchemaModel, response_base
from backend.common.security.jwt import DependsJwtAuth
from backend.utils.server_info import server_info
from backend.utils.format import fmt_bytes, fmt_seconds
from backend.utils.timezone import timezone
router = APIRouter()
@router.get('', summary='server 监控', dependencies=[DependsJwtAuth])
async def get_server_info() -> ResponseModel:
data = {
# 扔到线程池,避免阻塞
'cpu': await run_in_threadpool(server_info.get_cpu_info),
'mem': await run_in_threadpool(server_info.get_mem_info),
'sys': await run_in_threadpool(server_info.get_sys_info),
'disk': await run_in_threadpool(server_info.get_disk_info),
'service': await run_in_threadpool(server_info.get_service_info),
}
async def get_server_info() -> ResponseSchemaModel[ServerMonitorInfo]: # noqa: C901
def get_all_info() -> ServerMonitorInfo: # noqa: C901
# CPU 信息
cpu_data = {
'usage': round(psutil.cpu_percent(interval=0.1), 2),
'logical_num': psutil.cpu_count(logical=True) or 0,
'physical_num': psutil.cpu_count(logical=False) or 0,
'max_freq': 0.0,
'min_freq': 0.0,
'current_freq': 0.0,
}
try:
if hasattr(psutil, 'cpu_freq'):
cpu_freq = psutil.cpu_freq()
if cpu_freq:
cpu_data.update({
'max_freq': round(cpu_freq.max, 2),
'min_freq': round(cpu_freq.min, 2),
'current_freq': round(cpu_freq.current, 2),
})
except Exception:
pass
cpu = CpuInfo(**cpu_data)
# 内存信息
mem = psutil.virtual_memory()
gb_factor = 1024**3
mem_info = MemInfo(
total=round(mem.total / gb_factor, 2),
used=round(mem.used / gb_factor, 2),
free=round(mem.available / gb_factor, 2),
usage=round(mem.percent, 2),
)
# 系统信息
hostname = socket.gethostname()
ip = '127.0.0.1'
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.settimeout(0.5)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
except (TimeoutError, socket.gaierror, OSError):
pass
sys_info = SysInfo(name=hostname, ip=ip, os=platform.system(), arch=platform.machine())
# 磁盘信息
disk_list = []
exclude_fstypes = {'overlay', 'overlay2', 'tmpfs', 'devtmpfs', 'shm', 'proc', 'sysfs', 'cgroup', 'cgroup2'}
seen_devices = set()
for partition in psutil.disk_partitions(all=False):
# 跳过虚拟文件系统
if partition.fstype.lower() in exclude_fstypes:
continue
# 跳过重复设备(同一设备的不同挂载点)
if partition.device in seen_devices:
continue
try:
usage = psutil.disk_usage(partition.mountpoint)
if usage:
seen_devices.add(partition.device)
disk_list.append(
DiskInfo(
dir=partition.mountpoint,
type=partition.fstype,
device=partition.device,
total=fmt_bytes(usage.total),
free=fmt_bytes(usage.free),
used=fmt_bytes(usage.used),
usage=f'{usage.percent:.2f}%',
)
)
except (PermissionError, OSError):
continue
# 服务信息
process = psutil.Process(os.getpid())
proc_mem = process.memory_info()
try:
create_time = datetime.fromtimestamp(process.create_time(), tz=tz.utc)
start_time = timezone.from_datetime(create_time)
except (psutil.NoSuchProcess, OSError):
start_time = timezone.now()
elapsed = fmt_seconds(round((timezone.now() - start_time).total_seconds()))
service = ServiceInfo(
name='Python3',
version=platform.python_version(),
home=sys.executable,
cpu_usage=f'{process.cpu_percent(interval=0.1):.2f}%',
mem_vms=fmt_bytes(proc_mem.vms),
mem_rss=fmt_bytes(proc_mem.rss),
mem_free=fmt_bytes(proc_mem.vms - proc_mem.rss),
startup=timezone.to_str(start_time),
elapsed=elapsed,
)
return ServerMonitorInfo(cpu=cpu, mem=mem_info, sys=sys_info, disk=disk_list, service=service)
data = await run_in_threadpool(get_all_info)
return response_base.success(data=data)