server_info.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import os
  2. import platform
  3. import socket
  4. import sys
  5. from datetime import datetime, timedelta
  6. from datetime import timezone as tz
  7. from typing import List
  8. import psutil
  9. from utils.timezone import timezone
  10. class ServerInfo:
  11. @staticmethod
  12. def format_bytes(size) -> str:
  13. """格式化字节"""
  14. factor = 1024
  15. for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
  16. if abs(size) < factor:
  17. return f'{size:.2f} {unit}B'
  18. size /= factor
  19. return f'{size:.2f} YB'
  20. @staticmethod
  21. def fmt_seconds(seconds: int) -> str:
  22. days, rem = divmod(int(seconds), 86400)
  23. hours, rem = divmod(rem, 3600)
  24. minutes, seconds = divmod(rem, 60)
  25. parts = []
  26. if days:
  27. parts.append('{} 天'.format(days))
  28. if hours:
  29. parts.append('{} 小时'.format(hours))
  30. if minutes:
  31. parts.append('{} 分钟'.format(minutes))
  32. if seconds:
  33. parts.append('{} 秒'.format(seconds))
  34. if len(parts) == 0:
  35. return '0 秒'
  36. else:
  37. return ' '.join(parts)
  38. @staticmethod
  39. def fmt_timedelta(td: timedelta) -> str:
  40. """格式化时间差"""
  41. total_seconds = round(td.total_seconds())
  42. return ServerInfo.fmt_seconds(total_seconds)
  43. @staticmethod
  44. def get_cpu_info() -> dict:
  45. """获取 CPU 信息"""
  46. cpu_info = {'usage': round(psutil.cpu_percent(interval=1, percpu=False), 2)} # %
  47. # 检查是否是 Apple M系列芯片
  48. if platform.system() == 'Darwin' and 'arm' in platform.machine().lower():
  49. cpu_info['max_freq'] = 0
  50. cpu_info['min_freq'] = 0
  51. cpu_info['current_freq'] = 0
  52. else:
  53. try:
  54. # CPU 频率信息,最大、最小和当前频率
  55. cpu_freq = psutil.cpu_freq()
  56. cpu_info['max_freq'] = round(cpu_freq.max, 2) # MHz
  57. cpu_info['min_freq'] = round(cpu_freq.min, 2) # MHz
  58. cpu_info['current_freq'] = round(cpu_freq.current, 2) # MHz
  59. except FileNotFoundError:
  60. # 处理无法获取频率的情况
  61. cpu_info['max_freq'] = 0
  62. cpu_info['min_freq'] = 0
  63. cpu_info['current_freq'] = 0
  64. except AttributeError:
  65. # 处理属性不存在的情况(更安全的做法)
  66. cpu_info['max_freq'] = 0
  67. cpu_info['min_freq'] = 0
  68. cpu_info['current_freq'] = 0
  69. # CPU 逻辑核心数,物理核心数
  70. cpu_info['logical_num'] = psutil.cpu_count(logical=True)
  71. cpu_info['physical_num'] = psutil.cpu_count(logical=False)
  72. return cpu_info
  73. @staticmethod
  74. def get_mem_info() -> dict:
  75. """获取内存信息"""
  76. mem = psutil.virtual_memory()
  77. return {
  78. 'total': round(mem.total / 1024 / 1024 / 1024, 2), # GB
  79. 'used': round(mem.used / 1024 / 1024 / 1024, 2), # GB
  80. 'free': round(mem.available / 1024 / 1024 / 1024, 2), # GB
  81. 'usage': round(mem.percent, 2), # %
  82. }
  83. @staticmethod
  84. def get_sys_info() -> dict:
  85. """获取服务器信息"""
  86. try:
  87. with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sk:
  88. sk.connect(('8.8.8.8', 80))
  89. ip = sk.getsockname()[0]
  90. except socket.gaierror:
  91. ip = '127.0.0.1'
  92. return {'name': socket.gethostname(), 'ip': ip, 'os': platform.system(), 'arch': platform.machine()}
  93. @staticmethod
  94. def get_disk_info() -> List[dict]:
  95. """获取磁盘信息"""
  96. disk_info = []
  97. for disk in psutil.disk_partitions():
  98. usage = psutil.disk_usage(disk.mountpoint)
  99. disk_info.append({
  100. 'dir': disk.mountpoint,
  101. 'type': disk.fstype,
  102. 'device': disk.device,
  103. 'total': ServerInfo.format_bytes(usage.total),
  104. 'free': ServerInfo.format_bytes(usage.free),
  105. 'used': ServerInfo.format_bytes(usage.used),
  106. 'usage': f'{round(usage.percent, 2)} %',
  107. })
  108. return disk_info
  109. @staticmethod
  110. def get_service_info():
  111. """获取服务信息"""
  112. process = psutil.Process(os.getpid())
  113. mem_info = process.memory_info()
  114. start_time = timezone.f_datetime(datetime.utcfromtimestamp(process.create_time()).replace(tzinfo=tz.utc))
  115. return {
  116. 'name': 'Python3',
  117. 'version': platform.python_version(),
  118. 'home': sys.executable,
  119. 'cpu_usage': f'{round(process.cpu_percent(interval=1), 2)} %',
  120. 'mem_vms': ServerInfo.format_bytes(mem_info.vms), # 虚拟内存, 即当前进程申请的虚拟内存
  121. 'mem_rss': ServerInfo.format_bytes(mem_info.rss), # 常驻内存, 即当前进程实际使用的物理内存
  122. 'mem_free': ServerInfo.format_bytes(mem_info.vms - mem_info.rss), # 空闲内存
  123. 'startup': start_time,
  124. 'elapsed': f'{ServerInfo.fmt_timedelta(timezone.now() - start_time)}',
  125. }
  126. server_info = ServerInfo()