mirror of
https://github.com//cppla/ServerStatus
synced 2026-09-20 16:00:15 +08:00
chore: complete 2.0.2 maintenance baseline
This commit is contained in:
+46
-35
@@ -208,6 +208,34 @@ def get_cpu_model():
|
||||
return vendor
|
||||
return normalize_cpu_model(lscpu.get('architecture') or platform.machine() or platform.processor())
|
||||
|
||||
def get_os_name():
|
||||
try:
|
||||
sysname = platform.system().lower()
|
||||
if sysname.startswith('linux'):
|
||||
os_name = 'linux'
|
||||
try:
|
||||
with open('/etc/os-release') as f:
|
||||
for line in f:
|
||||
if line.startswith('ID='):
|
||||
value = line.strip().split('=', 1)[1].strip().strip('"')
|
||||
if value:
|
||||
os_name = value
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
return os_name
|
||||
if sysname.startswith('darwin'):
|
||||
return 'darwin'
|
||||
if sysname.startswith('freebsd'):
|
||||
return 'freebsd'
|
||||
if sysname.startswith('openbsd'):
|
||||
return 'openbsd'
|
||||
if sysname.startswith('netbsd'):
|
||||
return 'netbsd'
|
||||
return sysname or 'unknown'
|
||||
except Exception:
|
||||
return 'unknown'
|
||||
|
||||
def liuliang():
|
||||
NET_IN = 0
|
||||
NET_OUT = 0
|
||||
@@ -276,6 +304,22 @@ diskIO = {
|
||||
}
|
||||
monitorServer = {}
|
||||
|
||||
def update_net_speed(avgrx, avgtx, now_clock=None):
|
||||
if now_clock is None:
|
||||
now_clock = time.monotonic()
|
||||
previous_clock = netSpeed.get("clock", 0.0)
|
||||
previous_rx = netSpeed.get("avgrx", 0)
|
||||
previous_tx = netSpeed.get("avgtx", 0)
|
||||
diff = now_clock - previous_clock
|
||||
initialized = previous_clock > 0 and diff > 0
|
||||
netSpeed["diff"] = diff if initialized else 0.0
|
||||
netSpeed["clock"] = now_clock
|
||||
netSpeed["netrx"] = int((avgrx - previous_rx) / diff) if initialized and avgrx >= previous_rx else 0
|
||||
netSpeed["nettx"] = int((avgtx - previous_tx) / diff) if initialized and avgtx >= previous_tx else 0
|
||||
netSpeed["avgrx"] = avgrx
|
||||
netSpeed["avgtx"] = avgtx
|
||||
return netSpeed["netrx"], netSpeed["nettx"]
|
||||
|
||||
def _ping_thread(host, mark, port):
|
||||
lostPacket = 0
|
||||
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
|
||||
@@ -330,13 +374,7 @@ def _net_speed():
|
||||
dev = dev[1].split()
|
||||
avgrx += int(dev[0])
|
||||
avgtx += int(dev[8])
|
||||
now_clock = time.time()
|
||||
netSpeed["diff"] = now_clock - netSpeed["clock"]
|
||||
netSpeed["clock"] = now_clock
|
||||
netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
|
||||
netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
|
||||
netSpeed["avgrx"] = avgrx
|
||||
netSpeed["avgtx"] = avgtx
|
||||
update_net_speed(avgrx, avgtx)
|
||||
time.sleep(INTERVAL)
|
||||
|
||||
def _disk_io():
|
||||
@@ -617,34 +655,7 @@ if __name__ == '__main__':
|
||||
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
||||
array['io_read'] = diskIO.get("read")
|
||||
array['io_write'] = diskIO.get("write")
|
||||
# report OS (normalized)
|
||||
try:
|
||||
sysname = platform.system().lower()
|
||||
if sysname.startswith('linux'):
|
||||
os_name = 'linux'
|
||||
# try distro from os-release
|
||||
try:
|
||||
with open('/etc/os-release') as f:
|
||||
for line in f:
|
||||
if line.startswith('ID='):
|
||||
val = line.strip().split('=',1)[1].strip().strip('"')
|
||||
if val: os_name = val
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
elif sysname.startswith('darwin'):
|
||||
os_name = 'darwin'
|
||||
elif sysname.startswith('freebsd'):
|
||||
os_name = 'freebsd'
|
||||
elif sysname.startswith('openbsd'):
|
||||
os_name = 'openbsd'
|
||||
elif sysname.startswith('netbsd'):
|
||||
os_name = 'netbsd'
|
||||
else:
|
||||
os_name = sysname or 'unknown'
|
||||
except Exception:
|
||||
os_name = 'unknown'
|
||||
array['os'] = os_name
|
||||
array['os'] = get_os_name()
|
||||
items = []
|
||||
for _n, st in monitorServer.items():
|
||||
key = str(_n)
|
||||
|
||||
+44
-32
@@ -148,6 +148,32 @@ def get_cpu_model():
|
||||
return vendor
|
||||
return get_platform_cpu_arch()
|
||||
|
||||
def get_os_name():
|
||||
try:
|
||||
sysname = platform.system().lower()
|
||||
if sysname.startswith('windows'):
|
||||
return 'windows'
|
||||
if sysname.startswith('darwin') or 'mac' in sysname:
|
||||
return 'darwin'
|
||||
if 'bsd' in sysname:
|
||||
return 'bsd'
|
||||
if sysname.startswith('linux'):
|
||||
os_name = 'linux'
|
||||
try:
|
||||
with open('/etc/os-release') as f:
|
||||
for line in f:
|
||||
if line.startswith('ID='):
|
||||
value = line.strip().split('=', 1)[1].strip().strip('"')
|
||||
if value:
|
||||
os_name = value
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
return os_name
|
||||
return sysname or 'unknown'
|
||||
except Exception:
|
||||
return 'unknown'
|
||||
|
||||
def _get_net_io_counters():
|
||||
with _net_io_counters_lock:
|
||||
return psutil.net_io_counters(pernic=True)
|
||||
@@ -236,6 +262,22 @@ diskIO = {
|
||||
}
|
||||
monitorServer = {}
|
||||
|
||||
def update_net_speed(avgrx, avgtx, now_clock=None):
|
||||
if now_clock is None:
|
||||
now_clock = time.monotonic()
|
||||
previous_clock = netSpeed.get("clock", 0.0)
|
||||
previous_rx = netSpeed.get("avgrx", 0)
|
||||
previous_tx = netSpeed.get("avgtx", 0)
|
||||
diff = now_clock - previous_clock
|
||||
initialized = previous_clock > 0 and diff > 0
|
||||
netSpeed["diff"] = diff if initialized else 0.0
|
||||
netSpeed["clock"] = now_clock
|
||||
netSpeed["netrx"] = int((avgrx - previous_rx) / diff) if initialized and avgrx >= previous_rx else 0
|
||||
netSpeed["nettx"] = int((avgtx - previous_tx) / diff) if initialized and avgtx >= previous_tx else 0
|
||||
netSpeed["avgrx"] = avgrx
|
||||
netSpeed["avgtx"] = avgtx
|
||||
return netSpeed["netrx"], netSpeed["nettx"]
|
||||
|
||||
def _ping_thread(host, mark, port):
|
||||
lostPacket = 0
|
||||
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
|
||||
@@ -286,13 +328,7 @@ def _net_speed():
|
||||
continue
|
||||
avgrx += stats.bytes_recv
|
||||
avgtx += stats.bytes_sent
|
||||
now_clock = time.time()
|
||||
netSpeed["diff"] = now_clock - netSpeed["clock"]
|
||||
netSpeed["clock"] = now_clock
|
||||
netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
|
||||
netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
|
||||
netSpeed["avgrx"] = avgrx
|
||||
netSpeed["avgtx"] = avgtx
|
||||
update_net_speed(avgrx, avgtx)
|
||||
time.sleep(INTERVAL)
|
||||
|
||||
def _disk_io():
|
||||
@@ -570,31 +606,7 @@ if __name__ == '__main__':
|
||||
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
||||
array['io_read'] = diskIO.get("read")
|
||||
array['io_write'] = diskIO.get("write")
|
||||
# report OS (normalized)
|
||||
try:
|
||||
sysname = platform.system().lower()
|
||||
if sysname.startswith('windows'):
|
||||
os_name = 'windows'
|
||||
elif sysname.startswith('darwin') or 'mac' in sysname:
|
||||
os_name = 'darwin'
|
||||
elif 'bsd' in sysname:
|
||||
os_name = 'bsd'
|
||||
elif sysname.startswith('linux'):
|
||||
# try distro from os-release
|
||||
try:
|
||||
with open('/etc/os-release') as f:
|
||||
for line in f:
|
||||
if line.startswith('ID='):
|
||||
val = line.strip().split('=',1)[1].strip().strip('"')
|
||||
if val: os_name = val
|
||||
break
|
||||
except Exception:
|
||||
os_name = 'linux'
|
||||
else:
|
||||
os_name = sysname or 'unknown'
|
||||
except Exception:
|
||||
os_name = 'unknown'
|
||||
array['os'] = os_name
|
||||
array['os'] = get_os_name()
|
||||
items = []
|
||||
for _n, st in monitorServer.items():
|
||||
key = str(_n)
|
||||
|
||||
@@ -11,7 +11,7 @@ CLIENT_DIR = Path(__file__).resolve().parent
|
||||
|
||||
class ClientArgumentTests(unittest.TestCase):
|
||||
def test_password_with_user_text_does_not_replace_username(self):
|
||||
if importlib.util.find_spec("psutil") is None:
|
||||
if "psutil" not in sys.modules and importlib.util.find_spec("psutil") is None:
|
||||
sys.modules["psutil"] = types.ModuleType("psutil")
|
||||
|
||||
arguments = [
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import runpy
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
import unittest
|
||||
from collections import namedtuple
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
|
||||
CLIENT_DIR = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def load_client(filename):
|
||||
if filename == "client-psutil.py" and "psutil" not in sys.modules:
|
||||
try:
|
||||
__import__("psutil")
|
||||
except ImportError:
|
||||
sys.modules["psutil"] = types.ModuleType("psutil")
|
||||
return runpy.run_path(str(CLIENT_DIR / filename))
|
||||
|
||||
|
||||
class ClientMetricTests(unittest.TestCase):
|
||||
def test_psutil_counter_reads_are_serialized_and_keep_nowrap_enabled(self):
|
||||
client = load_client("client-psutil.py")
|
||||
active = 0
|
||||
maximum_active = 0
|
||||
calls = []
|
||||
state_lock = threading.Lock()
|
||||
|
||||
def fake_counters(*args, **kwargs):
|
||||
nonlocal active, maximum_active
|
||||
with state_lock:
|
||||
active += 1
|
||||
maximum_active = max(maximum_active, active)
|
||||
calls.append((args, kwargs))
|
||||
time.sleep(0.002)
|
||||
with state_lock:
|
||||
active -= 1
|
||||
return {}
|
||||
|
||||
with mock.patch.object(client["psutil"], "net_io_counters", side_effect=fake_counters, create=True):
|
||||
with ThreadPoolExecutor(max_workers=12) as executor:
|
||||
list(executor.map(lambda _index: client["_get_net_io_counters"](), range(48)))
|
||||
|
||||
self.assertEqual(maximum_active, 1)
|
||||
self.assertEqual(len(calls), 48)
|
||||
self.assertTrue(all(kwargs == {"pernic": True} for _args, kwargs in calls))
|
||||
|
||||
def test_psutil_totals_exclude_virtual_interfaces(self):
|
||||
client = load_client("client-psutil.py")
|
||||
counters = namedtuple("Counters", "bytes_sent bytes_recv")
|
||||
values = {
|
||||
"eth0": counters(500, 1000),
|
||||
"ens5": counters(300, 700),
|
||||
"lo": counters(9000, 9000),
|
||||
"docker0": counters(8000, 8000),
|
||||
"veth123": counters(7000, 7000),
|
||||
}
|
||||
with mock.patch.object(client["psutil"], "net_io_counters", return_value=values, create=True):
|
||||
self.assertEqual(client["liuliang"](), (1700, 800))
|
||||
|
||||
def test_linux_totals_read_proc_and_exclude_virtual_interfaces(self):
|
||||
client = load_client("client-linux.py")
|
||||
proc_net_dev = """Inter-| Receive | Transmit
|
||||
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
|
||||
eth0: 1000 10 0 0 0 0 0 0 500 5 0 0 0 0 0 0
|
||||
ens5: 700 7 0 0 0 0 0 0 300 3 0 0 0 0 0 0
|
||||
lo: 9000 9 0 0 0 0 0 0 9000 9 0 0 0 0 0 0
|
||||
veth123: 8000 8 0 0 0 0 0 0 8000 8 0 0 0 0 0 0
|
||||
"""
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data=proc_net_dev)):
|
||||
self.assertEqual(client["liuliang"](), (1700, 800))
|
||||
|
||||
def test_network_speed_starts_and_resets_at_zero(self):
|
||||
for filename in ("client-linux.py", "client-psutil.py"):
|
||||
with self.subTest(client=filename):
|
||||
client = load_client(filename)
|
||||
state = client["update_net_speed"].__globals__["netSpeed"]
|
||||
state.update({"clock": 0.0, "diff": 0.0, "avgrx": 0, "avgtx": 0, "netrx": 0, "nettx": 0})
|
||||
|
||||
self.assertEqual(client["update_net_speed"](1000, 1000, 100.0), (0, 0))
|
||||
self.assertEqual(client["update_net_speed"](1400, 1300, 102.0), (200, 150))
|
||||
self.assertEqual(client["update_net_speed"](10, 1500, 103.0), (0, 200))
|
||||
self.assertEqual(client["update_net_speed"](5, 4, 104.0), (0, 0))
|
||||
|
||||
def test_os_detection_uses_linux_distribution_id(self):
|
||||
os_release = 'NAME="Alpine Linux"\nID=alpine\nVERSION_ID=3.22\n'
|
||||
for filename in ("client-linux.py", "client-psutil.py"):
|
||||
with self.subTest(client=filename):
|
||||
client = load_client(filename)
|
||||
with mock.patch.object(client["platform"], "system", return_value="Linux"), \
|
||||
mock.patch("builtins.open", mock.mock_open(read_data=os_release)):
|
||||
self.assertEqual(client["get_os_name"](), "alpine")
|
||||
|
||||
def test_os_detection_has_platform_fallbacks(self):
|
||||
psutil_client = load_client("client-psutil.py")
|
||||
with mock.patch.object(psutil_client["platform"], "system", return_value="Windows Server 2022"):
|
||||
self.assertEqual(psutil_client["get_os_name"](), "windows")
|
||||
|
||||
linux_client = load_client("client-linux.py")
|
||||
with mock.patch.object(linux_client["platform"], "system", return_value="FreeBSD"):
|
||||
self.assertEqual(linux_client["get_os_name"](), "freebsd")
|
||||
|
||||
def test_cpu_model_prefers_specific_model_and_has_vendor_fallback(self):
|
||||
linux_client = load_client("client-linux.py")
|
||||
linux_globals = linux_client["get_cpu_model"].__globals__
|
||||
with mock.patch.dict(linux_globals, {
|
||||
"get_cpuinfo_values": lambda: {"model name": "AMD EPYC 7B13"},
|
||||
"get_lscpu_info": lambda: {"vendor id": "AuthenticAMD", "architecture": "x86_64"},
|
||||
}):
|
||||
self.assertEqual(linux_client["get_cpu_model"](), "AMD EPYC 7B13")
|
||||
|
||||
psutil_client = load_client("client-psutil.py")
|
||||
platform_module = psutil_client["platform"]
|
||||
uname = types.SimpleNamespace(processor="", machine="x86_64")
|
||||
with mock.patch.object(platform_module, "processor", return_value=""), \
|
||||
mock.patch.object(platform_module, "uname", return_value=uname), \
|
||||
mock.patch.object(platform_module, "machine", return_value="x86_64"), \
|
||||
mock.patch.object(platform_module, "platform", return_value="Linux GenuineIntel"):
|
||||
self.assertEqual(psutil_client["get_cpu_model"](), "GenuineIntel")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user