Build lightweight AI agent admin
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
服务器监控模块
|
||||
"""
|
||||
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
服务器监控API(异步版本)
|
||||
"""
|
||||
import asyncio
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from core.server_monitor.server_info import ServerInfoCollector
|
||||
from core.server_monitor.schema import (
|
||||
ServerMonitorResponseSchema,
|
||||
RealtimeStatsSchema,
|
||||
BatteryInfoSchema,
|
||||
BasicInfoSchema,
|
||||
CpuInfoSchema,
|
||||
MemoryInfoSchema,
|
||||
DiskInfoSchema,
|
||||
NetworkInfoSchema,
|
||||
ProcessInfoSchema,
|
||||
SystemLoadSchema,
|
||||
BootTimeSchema,
|
||||
UserInfoSchema,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/server_monitor", tags=["服务器监控"])
|
||||
|
||||
# 创建全局的服务器信息收集器实例
|
||||
server_collector = ServerInfoCollector()
|
||||
|
||||
|
||||
def _get_default_overview_error(error_msg: str) -> Dict[str, Any]:
|
||||
"""获取默认的错误响应"""
|
||||
return {
|
||||
"basic_info": {
|
||||
"hostname": "error",
|
||||
"ip_address": "error",
|
||||
"system": "error",
|
||||
"platform": error_msg,
|
||||
"architecture": "error",
|
||||
"processor": "error",
|
||||
"python_version": "error",
|
||||
"machine": "error",
|
||||
"node": "error",
|
||||
"release": "error",
|
||||
"version": "error"
|
||||
},
|
||||
"cpu_info": {
|
||||
"physical_cores": 0,
|
||||
"total_cores": 0,
|
||||
"cpu_percent": 0.0,
|
||||
"cpu_percent_per_core": [],
|
||||
"max_frequency": 0.0,
|
||||
"min_frequency": 0.0,
|
||||
"current_frequency": 0.0,
|
||||
"cpu_times": {},
|
||||
"cpu_stats": {}
|
||||
},
|
||||
"memory_info": {
|
||||
"virtual": {
|
||||
"total": 0.0,
|
||||
"available": 0.0,
|
||||
"used": 0.0,
|
||||
"free": 0.0,
|
||||
"percent": 0.0,
|
||||
"active": 0.0,
|
||||
"inactive": 0.0,
|
||||
"buffers": 0.0,
|
||||
"cached": 0.0,
|
||||
"shared": 0.0
|
||||
},
|
||||
"swap": {
|
||||
"total": 0.0,
|
||||
"used": 0.0,
|
||||
"free": 0.0,
|
||||
"percent": 0.0,
|
||||
"sin": 0.0,
|
||||
"sout": 0.0
|
||||
}
|
||||
},
|
||||
"disk_info": {
|
||||
"partitions": [],
|
||||
"total_read_bytes": 0.0,
|
||||
"total_write_bytes": 0.0,
|
||||
"total_read_count": 0,
|
||||
"total_write_count": 0
|
||||
},
|
||||
"network_info": {
|
||||
"total": {
|
||||
"bytes_sent": 0,
|
||||
"bytes_recv": 0,
|
||||
"packets_sent": 0,
|
||||
"packets_recv": 0,
|
||||
"errin": 0,
|
||||
"errout": 0,
|
||||
"dropin": 0,
|
||||
"dropout": 0
|
||||
},
|
||||
"per_interface": {},
|
||||
"interfaces": {},
|
||||
"connections": []
|
||||
},
|
||||
"process_info": {
|
||||
"total_processes": 0,
|
||||
"top_processes": [],
|
||||
"running_processes": 0,
|
||||
"sleeping_processes": 0
|
||||
},
|
||||
"system_load": {
|
||||
"load_1min": 0.0,
|
||||
"load_5min": 0.0,
|
||||
"load_15min": 0.0,
|
||||
"cpu_count": 0
|
||||
},
|
||||
"boot_time": {
|
||||
"boot_time": "",
|
||||
"uptime_seconds": 0,
|
||||
"uptime_formatted": "",
|
||||
"uptime_days": 0,
|
||||
"uptime_hours": 0,
|
||||
"uptime_minutes": 0
|
||||
},
|
||||
"users_info": [],
|
||||
"timestamp": ""
|
||||
}
|
||||
|
||||
|
||||
@router.get("/overview", response_model=ServerMonitorResponseSchema, summary="获取服务器完整监控信息")
|
||||
async def get_server_overview():
|
||||
"""获取服务器完整监控信息"""
|
||||
try:
|
||||
data = await asyncio.to_thread(server_collector.get_all_info)
|
||||
return data
|
||||
except Exception as e:
|
||||
print(f"Error in get_server_overview: {e}")
|
||||
return _get_default_overview_error(str(e))
|
||||
|
||||
|
||||
@router.get("/realtime", response_model=RealtimeStatsSchema, summary="获取实时统计信息")
|
||||
async def get_realtime_stats():
|
||||
"""获取实时统计信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_realtime_stats)
|
||||
except Exception as e:
|
||||
print(f"Error in get_realtime_stats: {e}")
|
||||
return {
|
||||
"cpu_percent": 0.0,
|
||||
"memory_percent": 0.0,
|
||||
"disk_io": {"read_speed": 0, "write_speed": 0},
|
||||
"network_io": {"upload_speed": 0, "download_speed": 0},
|
||||
"network_total": {"bytes_sent": 0, "bytes_recv": 0, "packets_sent": 0, "packets_recv": 0},
|
||||
"disk_total": {"read_bytes": 0, "write_bytes": 0, "read_count": 0, "write_count": 0},
|
||||
"cpu_details": {"current_frequency": 0, "cpu_percent_per_core": []},
|
||||
"memory_details": {"total": 0, "available": 0, "used": 0, "free": 0},
|
||||
"system_load": {"load_1min": 0, "load_5min": 0, "load_15min": 0},
|
||||
"process_stats": {"total_processes": 0, "running_processes": 0, "sleeping_processes": 0},
|
||||
"process_info": {"total_processes": 0, "top_processes": [], "running_processes": 0, "sleeping_processes": 0},
|
||||
"network_interfaces": {},
|
||||
"network_connections": [],
|
||||
"timestamp": ""
|
||||
}
|
||||
|
||||
|
||||
@router.get("/basic_info", response_model=BasicInfoSchema, summary="获取基础系统信息")
|
||||
async def get_basic_info():
|
||||
"""获取基础系统信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_basic_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/cpu_info", response_model=CpuInfoSchema, summary="获取CPU信息")
|
||||
async def get_cpu_info():
|
||||
"""获取CPU信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_cpu_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/memory_info", response_model=MemoryInfoSchema, summary="获取内存信息")
|
||||
async def get_memory_info():
|
||||
"""获取内存信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_memory_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/disk_info", response_model=DiskInfoSchema, summary="获取磁盘信息")
|
||||
async def get_disk_info():
|
||||
"""获取磁盘信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_disk_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/network_info", response_model=NetworkInfoSchema, summary="获取网络信息")
|
||||
async def get_network_info():
|
||||
"""获取网络信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_network_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/process_info", response_model=ProcessInfoSchema, summary="获取进程信息")
|
||||
async def get_process_info():
|
||||
"""获取进程信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_process_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/system_load", response_model=SystemLoadSchema, summary="获取系统负载信息")
|
||||
async def get_system_load():
|
||||
"""获取系统负载信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_system_load)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/boot_time", response_model=BootTimeSchema, summary="获取系统启动时间信息")
|
||||
async def get_boot_time():
|
||||
"""获取系统启动时间信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_boot_time)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/users_info", response_model=List[UserInfoSchema], summary="获取用户信息")
|
||||
async def get_users_info():
|
||||
"""获取用户信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_users_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/temperature_info", summary="获取温度信息")
|
||||
async def get_temperature_info():
|
||||
"""获取温度信息"""
|
||||
try:
|
||||
return await asyncio.to_thread(server_collector.get_temperature_info)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/battery_info", response_model=Optional[BatteryInfoSchema], summary="获取电池信息")
|
||||
async def get_battery_info():
|
||||
"""获取电池信息"""
|
||||
try:
|
||||
battery_info = await asyncio.to_thread(server_collector.get_battery_info)
|
||||
if battery_info:
|
||||
return battery_info
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
服务器监控Schema
|
||||
"""
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class BasicInfoSchema(BaseModel):
|
||||
"""基础系统信息"""
|
||||
hostname: str
|
||||
ip_address: str
|
||||
system: str
|
||||
platform: str
|
||||
architecture: str
|
||||
processor: str
|
||||
python_version: str
|
||||
machine: str
|
||||
node: str
|
||||
release: str
|
||||
version: str
|
||||
|
||||
|
||||
class CpuInfoSchema(BaseModel):
|
||||
"""CPU信息"""
|
||||
physical_cores: int
|
||||
total_cores: int
|
||||
cpu_percent: float
|
||||
cpu_percent_per_core: List[float]
|
||||
max_frequency: float
|
||||
min_frequency: float
|
||||
current_frequency: float
|
||||
cpu_times: Dict[str, Any]
|
||||
cpu_stats: Dict[str, Any]
|
||||
|
||||
|
||||
class MemoryVirtualSchema(BaseModel):
|
||||
"""虚拟内存信息"""
|
||||
total: float
|
||||
available: float
|
||||
used: float
|
||||
free: float
|
||||
percent: float
|
||||
active: float
|
||||
inactive: float
|
||||
buffers: float
|
||||
cached: float
|
||||
shared: float
|
||||
|
||||
|
||||
class MemorySwapSchema(BaseModel):
|
||||
"""交换内存信息"""
|
||||
total: float
|
||||
used: float
|
||||
free: float
|
||||
percent: float
|
||||
sin: float
|
||||
sout: float
|
||||
|
||||
|
||||
class MemoryInfoSchema(BaseModel):
|
||||
"""内存信息"""
|
||||
virtual: MemoryVirtualSchema
|
||||
swap: MemorySwapSchema
|
||||
|
||||
|
||||
class DiskPartitionSchema(BaseModel):
|
||||
"""磁盘分区信息"""
|
||||
device: str
|
||||
mountpoint: str
|
||||
file_system: str
|
||||
total_size: float
|
||||
used: float
|
||||
free: float
|
||||
percent: float
|
||||
|
||||
|
||||
class DiskInfoSchema(BaseModel):
|
||||
"""磁盘信息"""
|
||||
partitions: List[DiskPartitionSchema]
|
||||
total_read_bytes: float
|
||||
total_write_bytes: float
|
||||
total_read_count: int
|
||||
total_write_count: int
|
||||
total_read_time: Optional[int] = None
|
||||
total_write_time: Optional[int] = None
|
||||
|
||||
|
||||
class NetworkTotalSchema(BaseModel):
|
||||
"""网络总计信息"""
|
||||
bytes_sent: int
|
||||
bytes_recv: int
|
||||
packets_sent: int
|
||||
packets_recv: int
|
||||
errin: int
|
||||
errout: int
|
||||
dropin: int
|
||||
dropout: int
|
||||
|
||||
|
||||
class NetworkInterfaceStatsSchema(BaseModel):
|
||||
"""网络接口统计信息"""
|
||||
bytes_sent: int
|
||||
bytes_recv: int
|
||||
packets_sent: int
|
||||
packets_recv: int
|
||||
errin: int
|
||||
errout: int
|
||||
dropin: int
|
||||
dropout: int
|
||||
|
||||
|
||||
class NetworkAddressSchema(BaseModel):
|
||||
"""网络地址信息"""
|
||||
family: str
|
||||
address: str
|
||||
netmask: Optional[str] = None
|
||||
broadcast: Optional[str] = None
|
||||
|
||||
|
||||
class NetworkInterfaceStatsDetailSchema(BaseModel):
|
||||
"""网络接口详细统计"""
|
||||
is_up: bool
|
||||
duplex: str
|
||||
speed: int
|
||||
mtu: int
|
||||
|
||||
|
||||
class NetworkInterfaceSchema(BaseModel):
|
||||
"""网络接口信息"""
|
||||
addresses: List[NetworkAddressSchema]
|
||||
stats: NetworkInterfaceStatsDetailSchema
|
||||
|
||||
|
||||
class NetworkConnectionSchema(BaseModel):
|
||||
"""网络连接信息"""
|
||||
local_address: str
|
||||
status: str
|
||||
pid: Optional[int] = None
|
||||
|
||||
|
||||
class NetworkInfoSchema(BaseModel):
|
||||
"""网络信息"""
|
||||
total: NetworkTotalSchema
|
||||
per_interface: Dict[str, NetworkInterfaceStatsSchema]
|
||||
interfaces: Dict[str, NetworkInterfaceSchema]
|
||||
connections: List[NetworkConnectionSchema]
|
||||
|
||||
|
||||
class ProcessSchema(BaseModel):
|
||||
"""进程信息"""
|
||||
pid: int
|
||||
name: str
|
||||
cpu_percent: float
|
||||
memory_percent: float
|
||||
status: str
|
||||
create_time: str
|
||||
|
||||
|
||||
class ProcessInfoSchema(BaseModel):
|
||||
"""进程统计信息"""
|
||||
total_processes: int
|
||||
top_processes: List[ProcessSchema]
|
||||
running_processes: int
|
||||
sleeping_processes: int
|
||||
|
||||
|
||||
class SystemLoadSchema(BaseModel):
|
||||
"""系统负载信息"""
|
||||
load_1min: float
|
||||
load_5min: float
|
||||
load_15min: float
|
||||
cpu_count: int
|
||||
|
||||
|
||||
class BootTimeSchema(BaseModel):
|
||||
"""启动时间信息"""
|
||||
boot_time: str
|
||||
uptime_seconds: int
|
||||
uptime_formatted: str
|
||||
uptime_days: int
|
||||
uptime_hours: int
|
||||
uptime_minutes: int
|
||||
|
||||
|
||||
class UserInfoSchema(BaseModel):
|
||||
"""用户信息"""
|
||||
name: str
|
||||
terminal: Optional[str] = None
|
||||
host: Optional[str] = None
|
||||
started: Optional[str] = None
|
||||
pid: Optional[int] = None
|
||||
|
||||
|
||||
class BatteryInfoSchema(BaseModel):
|
||||
"""电池信息"""
|
||||
percent: float
|
||||
power_plugged: bool
|
||||
seconds_left: Optional[int] = None
|
||||
|
||||
|
||||
class RealtimeStatsSchema(BaseModel):
|
||||
"""实时统计信息"""
|
||||
cpu_percent: float
|
||||
memory_percent: float
|
||||
disk_io: Dict[str, float]
|
||||
network_io: Dict[str, float]
|
||||
network_total: Dict[str, int]
|
||||
disk_total: Dict[str, int]
|
||||
cpu_details: Dict[str, Any]
|
||||
memory_details: Dict[str, float]
|
||||
system_load: Dict[str, float]
|
||||
process_stats: Dict[str, int]
|
||||
process_info: ProcessInfoSchema
|
||||
network_interfaces: Dict[str, Dict[str, int]]
|
||||
network_connections: List[Dict[str, Any]]
|
||||
timestamp: str
|
||||
|
||||
|
||||
class ServerMonitorResponseSchema(BaseModel):
|
||||
"""服务器监控完整响应"""
|
||||
basic_info: BasicInfoSchema
|
||||
cpu_info: CpuInfoSchema
|
||||
memory_info: MemoryInfoSchema
|
||||
disk_info: DiskInfoSchema
|
||||
network_info: NetworkInfoSchema
|
||||
process_info: ProcessInfoSchema
|
||||
system_load: SystemLoadSchema
|
||||
boot_time: BootTimeSchema
|
||||
users_info: List[UserInfoSchema]
|
||||
timestamp: str
|
||||
@@ -0,0 +1,681 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
服务器信息收集器
|
||||
"""
|
||||
import platform
|
||||
import socket
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
class ServerInfoCollector:
|
||||
"""服务器信息收集器,支持Linux、Windows、macOS"""
|
||||
|
||||
def __init__(self):
|
||||
self.system_name = platform.system()
|
||||
self.is_windows = self.system_name == 'Windows'
|
||||
self.is_linux = self.system_name == 'Linux'
|
||||
self.is_macos = self.system_name == 'Darwin'
|
||||
|
||||
# 用于计算实时速度的缓存数据
|
||||
self._last_network_io = None
|
||||
self._last_network_time = None
|
||||
self._last_disk_io = None
|
||||
self._last_disk_time = None
|
||||
|
||||
# 用于CPU使用率的缓存数据
|
||||
self._last_cpu_times = None
|
||||
self._last_cpu_time = None
|
||||
|
||||
# 初始化CPU使用率监控
|
||||
try:
|
||||
psutil.cpu_percent(interval=None)
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_all_info(self) -> Dict[str, Any]:
|
||||
"""获取所有服务器监控信息"""
|
||||
return {
|
||||
'basic_info': self.get_basic_info(),
|
||||
'cpu_info': self.get_cpu_info(),
|
||||
'memory_info': self.get_memory_info(),
|
||||
'disk_info': self.get_disk_info(),
|
||||
'network_info': self.get_network_info(),
|
||||
'process_info': self.get_process_info(),
|
||||
'system_load': self.get_system_load(),
|
||||
'boot_time': self.get_boot_time(),
|
||||
'users_info': self.get_users_info(),
|
||||
'timestamp': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
def get_basic_info(self) -> Dict[str, Any]:
|
||||
"""获取基础系统信息"""
|
||||
try:
|
||||
hostname = socket.gethostname()
|
||||
ip_address = socket.gethostbyname(hostname)
|
||||
except:
|
||||
hostname = "unknown"
|
||||
ip_address = "unknown"
|
||||
|
||||
try:
|
||||
return {
|
||||
'hostname': hostname,
|
||||
'ip_address': ip_address,
|
||||
'system': platform.system(),
|
||||
'platform': platform.platform(),
|
||||
'architecture': platform.architecture()[0],
|
||||
'processor': platform.processor() or "Unknown",
|
||||
'python_version': platform.python_version(),
|
||||
'machine': platform.machine(),
|
||||
'node': platform.node(),
|
||||
'release': platform.release(),
|
||||
'version': platform.version(),
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error getting basic info: {e}")
|
||||
return {
|
||||
'hostname': hostname,
|
||||
'ip_address': ip_address,
|
||||
'system': "Unknown",
|
||||
'platform': "Unknown",
|
||||
'architecture': "Unknown",
|
||||
'processor': "Unknown",
|
||||
'python_version': "Unknown",
|
||||
'machine': "Unknown",
|
||||
'node': "Unknown",
|
||||
'release': "Unknown",
|
||||
'version': "Unknown",
|
||||
}
|
||||
|
||||
def get_cpu_info(self) -> Dict[str, Any]:
|
||||
"""获取CPU信息"""
|
||||
try:
|
||||
cpu_percent = psutil.cpu_percent(interval=1, percpu=True)
|
||||
overall_cpu_percent = psutil.cpu_percent(interval=1)
|
||||
|
||||
try:
|
||||
cpu_freq = psutil.cpu_freq()
|
||||
except (FileNotFoundError, OSError):
|
||||
cpu_freq = None
|
||||
|
||||
return {
|
||||
'physical_cores': psutil.cpu_count(logical=False) or 0,
|
||||
'total_cores': psutil.cpu_count(logical=True) or 0,
|
||||
'cpu_percent': round(overall_cpu_percent, 2),
|
||||
'cpu_percent_per_core': [round(x, 2) for x in cpu_percent] if cpu_percent else [],
|
||||
'max_frequency': round(cpu_freq.max, 2) if cpu_freq and cpu_freq.max else 0,
|
||||
'min_frequency': round(cpu_freq.min, 2) if cpu_freq and cpu_freq.min else 0,
|
||||
'current_frequency': round(cpu_freq.current, 2) if cpu_freq and cpu_freq.current else 0,
|
||||
'cpu_times': dict(psutil.cpu_times()._asdict()),
|
||||
'cpu_stats': dict(psutil.cpu_stats()._asdict()) if hasattr(psutil, 'cpu_stats') else {}
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error getting CPU info: {e}")
|
||||
return {
|
||||
'physical_cores': 0,
|
||||
'total_cores': 0,
|
||||
'cpu_percent': 0.0,
|
||||
'cpu_percent_per_core': [],
|
||||
'max_frequency': 0.0,
|
||||
'min_frequency': 0.0,
|
||||
'current_frequency': 0.0,
|
||||
'cpu_times': {},
|
||||
'cpu_stats': {}
|
||||
}
|
||||
|
||||
def get_memory_info(self) -> Dict[str, Any]:
|
||||
"""获取内存信息"""
|
||||
virtual_mem = psutil.virtual_memory()
|
||||
swap_mem = psutil.swap_memory()
|
||||
|
||||
return {
|
||||
'virtual': {
|
||||
'total': self._bytes_to_gb(virtual_mem.total),
|
||||
'available': self._bytes_to_gb(virtual_mem.available),
|
||||
'used': self._bytes_to_gb(virtual_mem.used),
|
||||
'free': self._bytes_to_gb(virtual_mem.free),
|
||||
'percent': round(virtual_mem.percent, 2),
|
||||
'active': self._bytes_to_gb(getattr(virtual_mem, 'active', 0)),
|
||||
'inactive': self._bytes_to_gb(getattr(virtual_mem, 'inactive', 0)),
|
||||
'buffers': self._bytes_to_gb(getattr(virtual_mem, 'buffers', 0)),
|
||||
'cached': self._bytes_to_gb(getattr(virtual_mem, 'cached', 0)),
|
||||
'shared': self._bytes_to_gb(getattr(virtual_mem, 'shared', 0)),
|
||||
},
|
||||
'swap': {
|
||||
'total': self._bytes_to_gb(swap_mem.total),
|
||||
'used': self._bytes_to_gb(swap_mem.used),
|
||||
'free': self._bytes_to_gb(swap_mem.free),
|
||||
'percent': round(swap_mem.percent, 2),
|
||||
'sin': self._bytes_to_mb(swap_mem.sin),
|
||||
'sout': self._bytes_to_mb(swap_mem.sout),
|
||||
}
|
||||
}
|
||||
|
||||
def get_disk_info(self) -> Dict[str, Any]:
|
||||
"""获取磁盘信息"""
|
||||
partitions = psutil.disk_partitions()
|
||||
disk_info = {
|
||||
'partitions': [],
|
||||
'total_read_bytes': 0,
|
||||
'total_write_bytes': 0,
|
||||
'total_read_count': 0,
|
||||
'total_write_count': 0,
|
||||
}
|
||||
|
||||
try:
|
||||
disk_io = psutil.disk_io_counters()
|
||||
if disk_io:
|
||||
disk_info.update({
|
||||
'total_read_bytes': self._bytes_to_gb(disk_io.read_bytes),
|
||||
'total_write_bytes': self._bytes_to_gb(disk_io.write_bytes),
|
||||
'total_read_count': disk_io.read_count,
|
||||
'total_write_count': disk_io.write_count,
|
||||
'total_read_time': disk_io.read_time,
|
||||
'total_write_time': disk_io.write_time,
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
for partition in partitions:
|
||||
try:
|
||||
partition_usage = psutil.disk_usage(partition.mountpoint)
|
||||
disk_info['partitions'].append({
|
||||
'device': partition.device,
|
||||
'mountpoint': partition.mountpoint,
|
||||
'file_system': partition.fstype,
|
||||
'total_size': self._bytes_to_gb(partition_usage.total),
|
||||
'used': self._bytes_to_gb(partition_usage.used),
|
||||
'free': self._bytes_to_gb(partition_usage.free),
|
||||
'percent': round(partition_usage.percent, 2),
|
||||
})
|
||||
except PermissionError:
|
||||
continue
|
||||
|
||||
return disk_info
|
||||
|
||||
def get_network_info(self) -> Dict[str, Any]:
|
||||
"""获取网络信息"""
|
||||
network_io = psutil.net_io_counters()
|
||||
per_nic = psutil.net_io_counters(pernic=True)
|
||||
|
||||
connections = []
|
||||
try:
|
||||
for conn in psutil.net_connections():
|
||||
if conn.status == 'LISTEN':
|
||||
connections.append({
|
||||
'local_address': f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else "",
|
||||
'status': conn.status,
|
||||
'pid': conn.pid
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
addresses = psutil.net_if_addrs()
|
||||
interface_stats = psutil.net_if_stats()
|
||||
|
||||
interfaces = {}
|
||||
for interface_name, interface_addresses in addresses.items():
|
||||
interfaces[interface_name] = {
|
||||
'addresses': [],
|
||||
'stats': {
|
||||
'is_up': False,
|
||||
'duplex': 'unknown',
|
||||
'speed': 0,
|
||||
'mtu': 0
|
||||
}
|
||||
}
|
||||
|
||||
for addr in interface_addresses:
|
||||
interfaces[interface_name]['addresses'].append({
|
||||
'family': str(addr.family),
|
||||
'address': addr.address,
|
||||
'netmask': addr.netmask,
|
||||
'broadcast': addr.broadcast,
|
||||
})
|
||||
|
||||
if interface_name in interface_stats:
|
||||
stat = interface_stats[interface_name]
|
||||
interfaces[interface_name]['stats'] = {
|
||||
'is_up': stat.isup,
|
||||
'duplex': str(stat.duplex),
|
||||
'speed': stat.speed,
|
||||
'mtu': stat.mtu,
|
||||
}
|
||||
|
||||
return {
|
||||
'total': {
|
||||
'bytes_sent': network_io.bytes_sent,
|
||||
'bytes_recv': network_io.bytes_recv,
|
||||
'packets_sent': network_io.packets_sent,
|
||||
'packets_recv': network_io.packets_recv,
|
||||
'errin': network_io.errin,
|
||||
'errout': network_io.errout,
|
||||
'dropin': network_io.dropin,
|
||||
'dropout': network_io.dropout,
|
||||
},
|
||||
'per_interface': {
|
||||
name: {
|
||||
'bytes_sent': stats.bytes_sent,
|
||||
'bytes_recv': stats.bytes_recv,
|
||||
'packets_sent': stats.packets_sent,
|
||||
'packets_recv': stats.packets_recv,
|
||||
'errin': stats.errin,
|
||||
'errout': stats.errout,
|
||||
'dropin': stats.dropin,
|
||||
'dropout': stats.dropout,
|
||||
}
|
||||
for name, stats in per_nic.items()
|
||||
},
|
||||
'interfaces': interfaces,
|
||||
'connections': connections[:50]
|
||||
}
|
||||
|
||||
def get_process_info(self) -> Dict[str, Any]:
|
||||
"""获取进程信息"""
|
||||
processes = []
|
||||
total_processes = 0
|
||||
running_processes = 0
|
||||
sleeping_processes = 0
|
||||
|
||||
try:
|
||||
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'status', 'create_time']):
|
||||
try:
|
||||
process_info = proc.info
|
||||
total_processes += 1
|
||||
|
||||
status = process_info.get('status', '')
|
||||
if status == psutil.STATUS_RUNNING:
|
||||
running_processes += 1
|
||||
elif status == psutil.STATUS_SLEEPING:
|
||||
sleeping_processes += 1
|
||||
|
||||
cpu_percent = process_info.get('cpu_percent', 0.0)
|
||||
memory_percent = process_info.get('memory_percent', 0.0)
|
||||
|
||||
if cpu_percent is None:
|
||||
cpu_percent = 0.0
|
||||
if memory_percent is None:
|
||||
memory_percent = 0.0
|
||||
|
||||
if cpu_percent > 1.0 or memory_percent > 1.0:
|
||||
create_time = process_info.get('create_time')
|
||||
if create_time:
|
||||
create_time_str = datetime.fromtimestamp(create_time).isoformat()
|
||||
else:
|
||||
create_time_str = datetime.now().isoformat()
|
||||
|
||||
processes.append({
|
||||
'pid': process_info.get('pid', 0),
|
||||
'name': process_info.get('name', 'Unknown'),
|
||||
'cpu_percent': round(float(cpu_percent), 2),
|
||||
'memory_percent': round(float(memory_percent), 2),
|
||||
'status': status or 'Unknown',
|
||||
'create_time': create_time_str,
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, TypeError, ValueError):
|
||||
continue
|
||||
|
||||
processes.sort(key=lambda x: x['cpu_percent'], reverse=True)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error getting process info: {e}")
|
||||
|
||||
return {
|
||||
'total_processes': total_processes,
|
||||
'top_processes': processes[:20],
|
||||
'running_processes': running_processes,
|
||||
'sleeping_processes': sleeping_processes,
|
||||
}
|
||||
|
||||
def get_system_load(self) -> Dict[str, Any]:
|
||||
"""获取系统负载信息"""
|
||||
try:
|
||||
if hasattr(psutil, 'getloadavg'):
|
||||
try:
|
||||
load_avg = psutil.getloadavg()
|
||||
return {
|
||||
'load_1min': round(load_avg[0], 2),
|
||||
'load_5min': round(load_avg[1], 2),
|
||||
'load_15min': round(load_avg[2], 2),
|
||||
'cpu_count': psutil.cpu_count() or 1
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
cpu_percent = psutil.cpu_percent(interval=0.1)
|
||||
cpu_count = psutil.cpu_count() or 1
|
||||
return {
|
||||
'load_1min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
'load_5min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
'load_15min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
'cpu_count': cpu_count
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error getting system load: {e}")
|
||||
return {
|
||||
'load_1min': 0.0,
|
||||
'load_5min': 0.0,
|
||||
'load_15min': 0.0,
|
||||
'cpu_count': 1
|
||||
}
|
||||
|
||||
def get_boot_time(self) -> Dict[str, Any]:
|
||||
"""获取系统启动时间信息"""
|
||||
try:
|
||||
boot_timestamp = psutil.boot_time()
|
||||
boot_datetime = datetime.fromtimestamp(boot_timestamp)
|
||||
uptime_seconds = int(time.time() - boot_timestamp)
|
||||
|
||||
days = uptime_seconds // 86400
|
||||
hours = (uptime_seconds % 86400) // 3600
|
||||
minutes = (uptime_seconds % 3600) // 60
|
||||
|
||||
return {
|
||||
'boot_time': boot_datetime.isoformat(),
|
||||
'uptime_seconds': uptime_seconds,
|
||||
'uptime_formatted': f"{days}天 {hours}小时 {minutes}分钟",
|
||||
'uptime_days': days,
|
||||
'uptime_hours': hours,
|
||||
'uptime_minutes': minutes,
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error getting boot time: {e}")
|
||||
return {
|
||||
'boot_time': datetime.now().isoformat(),
|
||||
'uptime_seconds': 0,
|
||||
'uptime_formatted': "0天 0小时 0分钟",
|
||||
'uptime_days': 0,
|
||||
'uptime_hours': 0,
|
||||
'uptime_minutes': 0,
|
||||
}
|
||||
|
||||
def get_users_info(self) -> List[Dict[str, Any]]:
|
||||
"""获取用户信息"""
|
||||
users = []
|
||||
try:
|
||||
for user in psutil.users():
|
||||
users.append({
|
||||
'name': user.name,
|
||||
'terminal': user.terminal,
|
||||
'host': user.host,
|
||||
'started': datetime.fromtimestamp(user.started).isoformat() if user.started else None,
|
||||
'pid': getattr(user, 'pid', None),
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
return users
|
||||
|
||||
def get_temperature_info(self) -> Dict[str, Any]:
|
||||
"""获取温度信息(如果支持的话)"""
|
||||
temps = {}
|
||||
try:
|
||||
if hasattr(psutil, 'sensors_temperatures'):
|
||||
sensors = psutil.sensors_temperatures()
|
||||
for name, entries in sensors.items():
|
||||
temps[name] = []
|
||||
for entry in entries:
|
||||
temps[name].append({
|
||||
'label': entry.label,
|
||||
'current': entry.current,
|
||||
'high': entry.high,
|
||||
'critical': entry.critical,
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
return temps
|
||||
|
||||
def get_battery_info(self) -> Optional[Dict[str, Any]]:
|
||||
"""获取电池信息(适用于笔记本电脑)"""
|
||||
try:
|
||||
if hasattr(psutil, 'sensors_battery'):
|
||||
battery = psutil.sensors_battery()
|
||||
if battery:
|
||||
return {
|
||||
'percent': battery.percent,
|
||||
'power_plugged': battery.power_plugged,
|
||||
'seconds_left': battery.secsleft if battery.secsleft != psutil.POWER_TIME_UNLIMITED else None,
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _bytes_to_gb(self, bytes_value: int) -> float:
|
||||
"""将字节转换为GB"""
|
||||
return round(bytes_value / (1024 ** 3), 2)
|
||||
|
||||
def _bytes_to_mb(self, bytes_value: int) -> float:
|
||||
"""将字节转换为MB"""
|
||||
return round(bytes_value / (1024 ** 2), 2)
|
||||
|
||||
def get_realtime_stats(self) -> Dict[str, Any]:
|
||||
"""获取实时统计信息(用于实时更新)"""
|
||||
current_time = time.time()
|
||||
|
||||
# 获取当前网络IO统计
|
||||
current_network_io = psutil.net_io_counters()
|
||||
upload_speed = 0.0
|
||||
download_speed = 0.0
|
||||
|
||||
if (self._last_network_io is not None and
|
||||
self._last_network_time is not None and
|
||||
current_network_io is not None):
|
||||
time_diff = current_time - self._last_network_time
|
||||
if time_diff > 0:
|
||||
bytes_sent_diff = current_network_io.bytes_sent - self._last_network_io.bytes_sent
|
||||
bytes_recv_diff = current_network_io.bytes_recv - self._last_network_io.bytes_recv
|
||||
|
||||
upload_speed = max(0, bytes_sent_diff / time_diff)
|
||||
download_speed = max(0, bytes_recv_diff / time_diff)
|
||||
|
||||
if current_network_io:
|
||||
self._last_network_io = current_network_io
|
||||
self._last_network_time = current_time
|
||||
|
||||
# 获取当前磁盘IO统计
|
||||
current_disk_io = psutil.disk_io_counters()
|
||||
read_speed = 0.0
|
||||
write_speed = 0.0
|
||||
|
||||
if (self._last_disk_io is not None and
|
||||
self._last_disk_time is not None and
|
||||
current_disk_io is not None):
|
||||
time_diff = current_time - self._last_disk_time
|
||||
if time_diff > 0:
|
||||
read_bytes_diff = current_disk_io.read_bytes - self._last_disk_io.read_bytes
|
||||
write_bytes_diff = current_disk_io.write_bytes - self._last_disk_io.write_bytes
|
||||
|
||||
read_speed = max(0, read_bytes_diff / time_diff)
|
||||
write_speed = max(0, write_bytes_diff / time_diff)
|
||||
|
||||
if current_disk_io:
|
||||
self._last_disk_io = current_disk_io
|
||||
self._last_disk_time = current_time
|
||||
|
||||
# 获取CPU详细信息
|
||||
cpu_percent_per_core = psutil.cpu_percent(interval=None, percpu=True)
|
||||
overall_cpu_percent = psutil.cpu_percent(interval=None)
|
||||
|
||||
if overall_cpu_percent == 0.0 and cpu_percent_per_core and not all(
|
||||
core == 0.0 for core in cpu_percent_per_core):
|
||||
overall_cpu_percent = sum(cpu_percent_per_core) / len(cpu_percent_per_core)
|
||||
|
||||
elif overall_cpu_percent == 0.0 and all(core == 0.0 for core in cpu_percent_per_core):
|
||||
try:
|
||||
overall_cpu_percent = psutil.cpu_percent(interval=0.1)
|
||||
cpu_percent_per_core = psutil.cpu_percent(interval=0.1, percpu=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
cpu_freq = psutil.cpu_freq()
|
||||
except (FileNotFoundError, OSError):
|
||||
cpu_freq = None
|
||||
|
||||
# 获取内存详细信息
|
||||
virtual_mem = psutil.virtual_memory()
|
||||
|
||||
# 获取系统负载
|
||||
load_info = {}
|
||||
try:
|
||||
if hasattr(psutil, 'getloadavg'):
|
||||
try:
|
||||
load_avg = psutil.getloadavg()
|
||||
load_info = {
|
||||
'load_1min': round(load_avg[0], 2),
|
||||
'load_5min': round(load_avg[1], 2),
|
||||
'load_15min': round(load_avg[2], 2),
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
if not load_info:
|
||||
cpu_percent = psutil.cpu_percent(interval=0.1)
|
||||
cpu_count = psutil.cpu_count() or 1
|
||||
load_info = {
|
||||
'load_1min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
'load_5min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
'load_15min': round(cpu_percent / 100 * cpu_count, 2),
|
||||
}
|
||||
except:
|
||||
load_info = {
|
||||
'load_1min': 0.0,
|
||||
'load_5min': 0.0,
|
||||
'load_15min': 0.0,
|
||||
}
|
||||
|
||||
# 获取进程统计信息
|
||||
total_processes = 0
|
||||
running_processes = 0
|
||||
sleeping_processes = 0
|
||||
top_processes = []
|
||||
|
||||
try:
|
||||
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'status', 'create_time']):
|
||||
try:
|
||||
process_info = proc.info
|
||||
total_processes += 1
|
||||
|
||||
status = process_info.get('status', '')
|
||||
if status == psutil.STATUS_RUNNING:
|
||||
running_processes += 1
|
||||
elif status == psutil.STATUS_SLEEPING:
|
||||
sleeping_processes += 1
|
||||
|
||||
cpu_percent = process_info.get('cpu_percent', 0.0)
|
||||
memory_percent = process_info.get('memory_percent', 0.0)
|
||||
|
||||
if cpu_percent is None:
|
||||
cpu_percent = 0.0
|
||||
if memory_percent is None:
|
||||
memory_percent = 0.0
|
||||
|
||||
if cpu_percent > 0.5 or memory_percent > 0.5:
|
||||
create_time = process_info.get('create_time')
|
||||
if create_time:
|
||||
create_time_str = datetime.fromtimestamp(create_time).isoformat()
|
||||
else:
|
||||
create_time_str = datetime.now().isoformat()
|
||||
|
||||
top_processes.append({
|
||||
'pid': process_info.get('pid', 0),
|
||||
'name': process_info.get('name', 'Unknown'),
|
||||
'cpu_percent': round(float(cpu_percent), 2),
|
||||
'memory_percent': round(float(memory_percent), 2),
|
||||
'status': status or 'Unknown',
|
||||
'create_time': create_time_str,
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, TypeError, ValueError):
|
||||
continue
|
||||
|
||||
top_processes.sort(key=lambda x: x['cpu_percent'], reverse=True)
|
||||
top_processes = top_processes[:15]
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error getting process info in realtime: {e}")
|
||||
|
||||
# 获取网络接口详细统计
|
||||
per_nic = psutil.net_io_counters(pernic=True)
|
||||
per_interface_stats = {}
|
||||
for name, stats in per_nic.items():
|
||||
per_interface_stats[name] = {
|
||||
'bytes_sent': stats.bytes_sent,
|
||||
'bytes_recv': stats.bytes_recv,
|
||||
'packets_sent': stats.packets_sent,
|
||||
'packets_recv': stats.packets_recv,
|
||||
'errin': stats.errin,
|
||||
'errout': stats.errout,
|
||||
'dropin': stats.dropin,
|
||||
'dropout': stats.dropout,
|
||||
}
|
||||
|
||||
# 获取网络连接
|
||||
connections = []
|
||||
try:
|
||||
for conn in psutil.net_connections():
|
||||
if conn.status == 'LISTEN':
|
||||
connections.append({
|
||||
'local_address': f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else "",
|
||||
'status': conn.status,
|
||||
'pid': conn.pid
|
||||
})
|
||||
if len(connections) >= 50:
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
return {
|
||||
'cpu_percent': round(overall_cpu_percent, 2),
|
||||
'memory_percent': round(virtual_mem.percent, 2),
|
||||
'disk_io': {
|
||||
'read_speed': read_speed,
|
||||
'write_speed': write_speed,
|
||||
},
|
||||
'network_io': {
|
||||
'upload_speed': upload_speed,
|
||||
'download_speed': download_speed,
|
||||
},
|
||||
'network_total': {
|
||||
'bytes_sent': current_network_io.bytes_sent if current_network_io else 0,
|
||||
'bytes_recv': current_network_io.bytes_recv if current_network_io else 0,
|
||||
'packets_sent': current_network_io.packets_sent if current_network_io else 0,
|
||||
'packets_recv': current_network_io.packets_recv if current_network_io else 0,
|
||||
},
|
||||
'disk_total': {
|
||||
'read_bytes': current_disk_io.read_bytes if current_disk_io else 0,
|
||||
'write_bytes': current_disk_io.write_bytes if current_disk_io else 0,
|
||||
'read_count': current_disk_io.read_count if current_disk_io else 0,
|
||||
'write_count': current_disk_io.write_count if current_disk_io else 0,
|
||||
},
|
||||
'cpu_details': {
|
||||
'current_frequency': round(cpu_freq.current, 2) if cpu_freq and cpu_freq.current else 0,
|
||||
'cpu_percent_per_core': [round(x, 2) for x in cpu_percent_per_core] if cpu_percent_per_core else [],
|
||||
},
|
||||
'memory_details': {
|
||||
'total': self._bytes_to_gb(virtual_mem.total),
|
||||
'available': self._bytes_to_gb(virtual_mem.available),
|
||||
'used': self._bytes_to_gb(virtual_mem.used),
|
||||
'free': self._bytes_to_gb(virtual_mem.free),
|
||||
},
|
||||
'system_load': load_info,
|
||||
'process_stats': {
|
||||
'total_processes': total_processes,
|
||||
'running_processes': running_processes,
|
||||
'sleeping_processes': sleeping_processes,
|
||||
},
|
||||
'process_info': {
|
||||
'total_processes': total_processes,
|
||||
'top_processes': top_processes,
|
||||
'running_processes': running_processes,
|
||||
'sleeping_processes': sleeping_processes,
|
||||
},
|
||||
'network_interfaces': per_interface_stats,
|
||||
'network_connections': connections,
|
||||
'timestamp': datetime.now().isoformat()
|
||||
}
|
||||
Reference in New Issue
Block a user