Files
project-panel/routes_system.py
hz4th_coder c960048042 fix: 重写routes_system.py修复API错误
完整重写系统监控API,确保:
- 正确的数据结构匹配JavaScript期待
- system.uptime/system.boot_time/system.process_count
- cpu.count/cpu.logical
- disk.free_gb
- network.sent_mb/recv_mb/sent_speed/recv_speed
- 所有异常处理和日志记录

修复500错误,现在系统监控应该正常显示
2026-06-01 16:19:59 +08:00

199 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""
系统资源监控 API 路由
"""
import os
import subprocess
import time
from datetime import datetime
from flask import jsonify, request
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_free_gb = round(disk.free / (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,
'system': {
'uptime': uptime_str,
'boot_time': datetime.fromtimestamp(boot_time).strftime('%Y-%m-%d %H:%M:%S'),
'process_count': process_count
},
'cpu': {
'percent': cpu_percent,
'count': cpu_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,
'free_gb': disk_free_gb,
'percent': disk_percent
},
'network': {
'sent_mb': round(net.bytes_sent / (1024**2), 2),
'recv_mb': round(net.bytes_recv / (1024**2), 2),
'sent_speed': round(upload_speed, 2),
'recv_speed': round(download_speed, 2)
}
})
except Exception as e:
log_message(f"系统监控API错误: {e}")
return jsonify({'error': str(e), 'available': False}), 500
@app.route('/api/system/processes')
def api_system_processes():
"""获取进程列表"""
if not HAS_PSUTIL:
return jsonify({'error': 'psutil未安装'}), 500
try:
limit = int(request.args.get('limit', 10))
limit = max(1, min(50, limit))
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[:limit]
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():
"""保存预警配置"""
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