Files
project-panel/routes_system.py
hz4th_coder 69edd1c63e refactor: 模块化重构 v3.4.0
🎯 重构目标:
- 将 3700+ 行单文件拆分为多个模块
- 清晰的职责分离,便于维护和扩展

📁 模块结构:
- config.py: 配置常量和路径
- database.py: 数据库操作
- utils.py: 工具函数(日志、进程、cron等)
- routes_cron.py: Cron管理API
- routes_system.py: 系统监控API
- routes_config.py: 配置管理API
- routes_email.py: 邮件通知API
- routes_project.py: 项目管理API
- templates.py: HTML模板
- app.py: 主入口文件

 优势:
- 易于维护:每个模块职责明确
- 易于扩展:新增功能只需添加对应模块
- 易于测试:模块独立,便于单元测试
- 易于理解:新人能快速上手

📝 更新 README.md,详细说明项目结构和API接口
2026-06-01 12:30:24 +08:00

188 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""
系统资源监控 API 路由
"""
import os
import subprocess
import time
from flask import jsonify
from utils import log_message, get_cpu_temperatures, load_alert_config
try:
import psutil
HAS_PSUTIL = True
_last_net_stats = {'bytes_sent': 0, 'bytes_recv': 0, 'time': 0}
except ImportError:
HAS_PSUTIL = False
def register_system_routes(app):
"""注册系统监控相关路由"""
@app.route('/api/system/stats')
def api_system_stats():
"""获取系统资源信息"""
if not HAS_PSUTIL:
return jsonify({'error': 'psutil未安装', 'available': False})
try:
# CPU
cpu_percent = psutil.cpu_percent(interval=0.5)
cpu_count = psutil.cpu_count(logical=False) or psutil.cpu_count()
cpu_count_logical = psutil.cpu_count(logical=True)
# CPU 温度
cpu_temps = get_cpu_temperatures()
# 内存
mem = psutil.virtual_memory()
mem_total_gb = round(mem.total / (1024**3), 2)
mem_used_gb = round(mem.used / (1024**3), 2)
mem_available_gb = round(mem.available / (1024**3), 2)
mem_percent = mem.percent
# 磁盘
disk = psutil.disk_usage('/')
disk_total_gb = round(disk.total / (1024**3), 2)
disk_used_gb = round(disk.used / (1024**3), 2)
disk_percent = disk.percent
# 网速(需要计算差值)
global _last_net_stats
current_time = time.time()
net = psutil.net_io_counters()
if _last_net_stats['time'] > 0:
time_diff = current_time - _last_net_stats['time']
bytes_sent_diff = net.bytes_sent - _last_net_stats['bytes_sent']
bytes_recv_diff = net.bytes_recv - _last_net_stats['bytes_recv']
upload_speed = (bytes_sent_diff / time_diff) / 1024 # KB/s
download_speed = (bytes_recv_diff / time_diff) / 1024 # KB/s
else:
upload_speed = 0
download_speed = 0
_last_net_stats = {
'bytes_sent': net.bytes_sent,
'bytes_recv': net.bytes_recv,
'time': current_time
}
# 进程数量
process_count = len(psutil.pids())
# 系统启动时间
boot_time = psutil.boot_time()
uptime_seconds = time.time() - boot_time
uptime_hours = int(uptime_seconds // 3600)
uptime_days = int(uptime_hours // 24)
uptime_str = f"{uptime_days}{uptime_hours % 24}小时"
return jsonify({
'available': True,
'cpu': {
'percent': cpu_percent,
'count_physical': cpu_count,
'count_logical': cpu_count_logical,
'temp_package_0': cpu_temps.get('package_0'),
'temp_package_1': cpu_temps.get('package_1')
},
'memory': {
'total_gb': mem_total_gb,
'used_gb': mem_used_gb,
'available_gb': mem_available_gb,
'percent': mem_percent
},
'disk': {
'total_gb': disk_total_gb,
'used_gb': disk_used_gb,
'percent': disk_percent
},
'network': {
'upload_speed_kb': round(upload_speed, 2),
'download_speed_kb': round(download_speed, 2)
},
'process_count': process_count,
'uptime': uptime_str
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/system/processes')
def api_system_processes():
"""获取进程列表"""
if not HAS_PSUTIL:
return jsonify({'error': 'psutil未安装'}), 500
try:
processes = []
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'status']):
try:
processes.append({
'pid': proc.info['pid'],
'name': proc.info['name'],
'cpu': proc.info['cpu_percent'] or 0,
'memory': proc.info['memory_percent'] or 0,
'status': proc.info['status']
})
except:
pass
# 按CPU排序
processes.sort(key=lambda x: x['cpu'], reverse=True)
processes = processes[:50] # 只返回前50个
return jsonify({'processes': processes})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/system/docker')
def api_system_docker():
"""获取 Docker 容器状态"""
try:
result = subprocess.run(['docker', 'ps', '--format', '{{.Names}}|{{.Status}}|{{.Ports}}'],
capture_output=True, text=True, timeout=5)
containers = []
for line in result.stdout.strip().split('\n'):
if line:
parts = line.split('|')
if len(parts) >= 2:
containers.append({
'name': parts[0],
'status': parts[1],
'ports': parts[2] if len(parts) > 2 else ''
})
return jsonify({'containers': containers})
except Exception as e:
return jsonify({'error': str(e), 'containers': []})
@app.route('/api/alerts', methods=['GET'])
def api_get_alerts():
"""获取预警配置"""
config = load_alert_config()
return jsonify(config)
@app.route('/api/alerts', methods=['POST'])
def api_save_alerts():
"""保存预警配置"""
from flask import request
import json
from config import ALERT_CONFIG_FILE
try:
data = request.get_json()
config = load_alert_config()
if 'thresholds' in data:
config['thresholds'] = data['thresholds']
if 'web_settings' in data:
config['web_settings'] = data['web_settings']
with open(ALERT_CONFIG_FILE, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
return jsonify({'message': '保存成功'})
except Exception as e:
return jsonify({'error': str(e)}), 500