diff --git a/backend/app/api/v1/monitor/redis.py b/backend/app/api/v1/monitor/redis.py index c8dc636b..3719fd91 100644 --- a/backend/app/api/v1/monitor/redis.py +++ b/backend/app/api/v1/monitor/redis.py @@ -3,25 +3,13 @@ from fastapi import APIRouter from backend.app.common.jwt import DependsJwtAuth -from backend.app.common.redis import redis_client from backend.app.common.response.response_schema import response_base +from backend.app.utils.redis_info import redis_info router = APIRouter() @router.get('/redis', summary='redis 监控', dependencies=[DependsJwtAuth]) -async def redis_info(): - info = await redis_client.info() - fmt_info = {} - for key, value in info.items(): - if isinstance(value, dict): - value = ','.join({f'{k}={v}' for k, v in value.items()}) - else: - value = str(value) - fmt_info[key] = value - db_size = await redis_client.dbsize() - command_stats = await redis_client.info('commandstats') - stats_list = [] - for k, v in command_stats.items(): - stats_list.append({'name': k.split('_')[-1], 'value': str(v.get('calls', ''))}) - return await response_base.success(data={'info': fmt_info, 'stats': stats_list, 'size': db_size}) +async def get_redis_info(): + data = {'info': await redis_info.get_info(), 'stats': await redis_info.get_stats()} + return await response_base.success(data=data) diff --git a/backend/app/api/v1/monitor/server.py b/backend/app/api/v1/monitor/server.py index 773608af..9e06917b 100644 --- a/backend/app/api/v1/monitor/server.py +++ b/backend/app/api/v1/monitor/server.py @@ -5,19 +5,19 @@ from starlette.concurrency import run_in_threadpool from backend.app.common.jwt import DependsJwtAuth from backend.app.common.response.response_schema import response_base -from backend.app.utils.server_info import ServerInfo +from backend.app.utils.server_info import server_info router = APIRouter() @router.get('/server', summary='server 监控', dependencies=[DependsJwtAuth]) -async def server_info(): +async def get_server_info(): """IO密集型任务,使用线程池尽量减少性能损耗""" data = { - 'cpu': await run_in_threadpool(ServerInfo.get_cpu_info), - 'mem': await run_in_threadpool(ServerInfo.get_mem_info), - 'sys': await run_in_threadpool(ServerInfo.get_sys_info), - 'disk': await run_in_threadpool(ServerInfo.get_disk_info), - 'service': await run_in_threadpool(ServerInfo.get_service_info), + '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), } return await response_base.success(data=data) diff --git a/backend/app/utils/redis_info.py b/backend/app/utils/redis_info.py new file mode 100644 index 00000000..fbc82531 --- /dev/null +++ b/backend/app/utils/redis_info.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from backend.app.common.redis import redis_client +from backend.app.utils.server_info import server_info + + +class RedisInfo: + + @staticmethod + async def get_info(): + info = await redis_client.info() + fmt_info = {} + for key, value in info.items(): + if isinstance(value, dict): + value = ','.join({f'{k}={v}' for k, v in value.items()}) + else: + value = str(value) + fmt_info[key] = value + db_size = await redis_client.dbsize() + fmt_info.update({'keys_num': db_size}) + fmt_uptime = server_info.fmt_seconds(fmt_info.get('uptime_in_seconds', 0)) + fmt_info.update({'uptime_in_seconds': fmt_uptime}) + return fmt_info + + @staticmethod + async def get_stats(): + stats_list = [] + command_stats = await redis_client.info('commandstats') + for k, v in command_stats.items(): + stats_list.append({'name': k.split('_')[-1], 'value': str(v.get('calls', ''))}) + return stats_list + + +redis_info = RedisInfo() diff --git a/backend/app/utils/server_info.py b/backend/app/utils/server_info.py index 0a98d987..61c78e74 100644 --- a/backend/app/utils/server_info.py +++ b/backend/app/utils/server_info.py @@ -22,10 +22,8 @@ class ServerInfo: return f'{size:.2f} YB' @staticmethod - def fmt_timedelta(td: timedelta) -> str: - """格式化时间差""" - total_seconds = round(td.total_seconds()) - days, rem = divmod(total_seconds, 86400) + def fmt_seconds(seconds: int) -> str: + days, rem = divmod(int(seconds), 86400) hours, rem = divmod(rem, 3600) minutes, seconds = divmod(rem, 60) parts = [] @@ -42,16 +40,22 @@ class ServerInfo: else: return ' '.join(parts) + @staticmethod + def fmt_timedelta(td: timedelta) -> str: + """格式化时间差""" + total_seconds = round(td.total_seconds()) + return ServerInfo.fmt_seconds(total_seconds) + @staticmethod def get_cpu_info() -> dict: """获取 CPU 信息""" - cpu_info = {'usage': f'{round(psutil.cpu_percent(interval=1, percpu=False), 2)} %'} + cpu_info = {'usage': round(psutil.cpu_percent(interval=1, percpu=False), 2)} # % # CPU 频率信息,最大、最小和当前频率 cpu_freq = psutil.cpu_freq() - cpu_info['max_freq'] = f'{round(cpu_freq.max, 2)} MHz' - cpu_info['min_freq'] = f'{round(cpu_freq.min, 2)} MHz' - cpu_info['current_freq'] = f'{round(cpu_freq.current, 2)} MHz' + cpu_info['max_freq'] = round(cpu_freq.max, 2) # MHz + cpu_info['min_freq'] = round(cpu_freq.min, 2) # MHz + cpu_info['current_freq'] = round(cpu_freq.current, 2) # MHz # CPU 逻辑核心数,物理核心数 cpu_info['logical_num'] = psutil.cpu_count(logical=True) @@ -63,10 +67,10 @@ class ServerInfo: """获取内存信息""" mem = psutil.virtual_memory() return { - 'total': ServerInfo.format_bytes(mem.total), - 'used': ServerInfo.format_bytes(mem.used), - 'free': ServerInfo.format_bytes(mem.available), - 'usage': f'{round(mem.percent, 2)} %', + 'total': round(mem.total / 1024 / 1024 / 1024, 2), # GB + 'used': round(mem.used / 1024 / 1024 / 1024, 2), # GB + 'free': round(mem.available / 1024 / 1024 / 1024, 2), # GB + 'usage': round(mem.percent, 2), # % } @staticmethod @@ -116,3 +120,6 @@ class ServerInfo: 'startup': start_time, 'elapsed': f'{ServerInfo.fmt_timedelta(timezone_utils.get_timezone_datetime() - start_time)}', } + + +server_info = ServerInfo() diff --git a/backend/sql/init_test_data.sql b/backend/sql/init_test_data.sql index 82b1ab00..51b4df88 100644 --- a/backend/sql/init_test_data.sql +++ b/backend/sql/init_test_data.sql @@ -1,7 +1,7 @@ INSERT INTO fba.sys_dept (id, name, level, sort, leader, phone, email, status, del_flag, parent_id, created_time, updated_time) VALUES (1, 'test', 0, 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null); -insert into fba.sys_menu (id, name, level, sort, icon, path, menu_type, component, perms, status, remark, parent_id, created_time, updated_time, show, cache, title) +INSERT INTO fba.sys_menu (id, name, level, sort, icon, path, menu_type, component, perms, status, remark, parent_id, created_time, updated_time, show, cache, title) values (1, 'test', 0, 0, null, null, 0, null, null, 1, null, null, '2023-06-26 17:13:45', null, 0, 1, '测试'), (2, 'dashboard', 0, 0, 'icon-dashboard', '/dashboard', 0, '/dashboard/workplace/index.vue', null, 1, null, null, '2023-06-30 10:10:34', null, 1, 1, '仪表盘'), (3, 'Workplace', 0, 0, null, '/workplace', 1, null, null, 1, null, 2, '2023-06-30 10:11:40', null, 1, 1, '工作台'), @@ -18,6 +18,10 @@ values (1, 'test', 0, 0, null, null, 0, null, null, 1, null, null, '2023-06-26 (14, '', 0, 0, null, null, 2, null, null, 1, null, 11, '2023-07-07 20:16:27', null, 1, 1, '测试6'), (15, 'Opera', 0, 0, null, '/opera', 1, '/log/opera/index.vue', null, 1, null, 5, '2023-07-07 20:28:21', null, 1, 1, '操作日志'), (16, 'SysDept', 0, 0, null, 'sys-dept', 1, '/admin/dept/index.vue', null, 1, null, 8, '2023-07-08 22:43:20', null, 1, 1, '部门管理'); + (17, 'SysApi', 0, 1, null, 'sys-api', 1, '/admin/api/index.vue', null, 1, null, 8, '2023-07-10 13:10:16', null, 1, 1, 'API管理'); + (18, 'monitor', 0, 88, 'icon-computer', null, 0, null, null, 1, null, null, '2023-07-11 20:20:20', null, 1, 1, '系统监控'), + (19, 'Redis', 0, 0, null, null, 1, '/monitor/redis/index.vue', null, 1, null, 18, '2023-07-11 20:21:28', null, 1, 1, 'Redis监控'), + (20, 'Server', 0, 0, null, 'server', 1, '/monitor/server/index.vue', null, 1, null, 18, '2023-07-11 20:23:43', null, 1, 1, '服务器监控'); INSERT INTO fba.sys_role (id, name, data_scope, status, remark, created_time, updated_time) VALUES (1, 'test', 2, 1, null, '2023-06-26 17:13:45', null);