from __future__ import annotations from typing import Any from core.config import THRESHOLDS, load_hosts, settings_payload, utc_now from .host_metrics import get_host_metrics from .http_probe import get_service_payload from .mongo_metrics import get_mongo_payload from .mysql_metrics import get_mysql_overview_payload from .nacos import get_nacos_payload def classify_threshold(value: float | int | None, thresholds: dict[str, float | int]) -> str: # 没值时返回 neutral。 if value is None: return "neutral" # 读取 warn 阈值。 warn = float(thresholds["warn"]) # 读取 bad 阈值。 bad = float(thresholds["bad"]) # 统一转成浮点数比较。 numeric = float(value) # 超过 bad 阈值记为 bad。 if numeric >= bad: return "bad" # 超过 warn 阈值记为 warn。 if numeric >= warn: return "warn" # 其余情况记为 ok。 return "ok" def annotate_metric_levels(metrics: dict[str, Any]) -> dict[str, Any]: # 复制一份,避免直接修改缓存原对象。 payload = dict(metrics) # 指标采集失败时统一按 bad 标记。 if not payload.get("ok"): payload["cpuLevel"] = "bad" payload["memoryLevel"] = "bad" payload["diskLevel"] = "bad" payload["processLevel"] = "bad" return payload # 给 CPU 指标增加级别。 payload["cpuLevel"] = classify_threshold(payload.get("cpuPercent"), THRESHOLDS["cpuPercent"]) # 给内存指标增加级别。 payload["memoryLevel"] = classify_threshold(payload.get("memoryPercent"), THRESHOLDS["memoryPercent"]) # 给磁盘指标增加级别。 payload["diskLevel"] = classify_threshold(payload.get("diskPercent"), THRESHOLDS["diskPercent"]) # 给进程数增加级别。 payload["processLevel"] = classify_threshold(payload.get("processCount"), THRESHOLDS["processCount"]) # 返回加完等级的结构。 return payload def build_host_payload( hosts: list[dict[str, Any]], service_payload: dict[str, Any], metrics_by_host: dict[str, dict[str, Any]], ) -> list[dict[str, Any]]: # 先把服务结果按 host 分组。 services_by_host: dict[str, list[dict[str, Any]]] = {} # 遍历所有服务结果。 for item in service_payload.get("items") or []: services_by_host.setdefault(item["host"], []).append(item) # 最终的主机维度结果。 grouped_hosts: list[dict[str, Any]] = [] # 按配置顺序输出主机。 for host in hosts: # 当前主机的服务结果列表。 items = services_by_host.get(host["host"], []) # 当前主机健康服务数量。 ok_count = sum(1 for item in items if item["ok"]) # 当前主机原始指标。 raw_metrics = metrics_by_host.get(host["host"], {"ok": False, "error": "metrics unavailable"}) # 加上指标阈值等级。 metrics = annotate_metric_levels(raw_metrics) # 追加主机结构。 grouped_hosts.append( { "host": host["host"], "ip": host["ip"], "group": host["group"], "instanceId": host["instanceId"], "metrics": metrics, "serviceSummary": { "total": len(items), "ok": ok_count, "down": len(items) - ok_count, }, "items": items, } ) # 返回主机分组结果。 return grouped_hosts def build_monitor_payload() -> dict[str, Any]: # 读取当前监控目标。 hosts = load_hosts() # 获取服务探测结果。 service_payload = get_service_payload(hosts, THRESHOLDS["latencyMs"]) # 获取主机资源指标。 metrics_by_host = get_host_metrics(hosts) # 获取 Nacos 注册信息。 nacos_payload = get_nacos_payload() # 获取 Mongo 指标。 mongo_payload = get_mongo_payload() # 获取 MySQL 指标。 mysql_payload = get_mysql_overview_payload() # 组装主机维度视图。 grouped_hosts = build_host_payload(hosts, service_payload, metrics_by_host) # 统计主机指标成功数。 host_metric_ok = sum(1 for host in grouped_hosts if host["metrics"].get("ok")) # 返回完整的页面 API 载荷。 return { "updatedAt": utc_now(), "settings": settings_payload(), "summary": { **service_payload["summary"], "hostMetricOk": host_metric_ok, "hostMetricDown": len(grouped_hosts) - host_metric_ok, "nacosServiceTotal": int(nacos_payload.get("summary", {}).get("serviceTotal", 0)), "nacosInstanceTotal": int(nacos_payload.get("summary", {}).get("instanceTotal", 0)), "nacosUnhealthyInstanceTotal": int( nacos_payload.get("summary", {}).get("unhealthyInstanceTotal", 0) ), "mongoDatabaseTotal": int(mongo_payload.get("summary", {}).get("databaseTotal", 0)), "mongoCollectionTotal": int(mongo_payload.get("summary", {}).get("collectionTotal", 0)), "mongoOk": 1 if mongo_payload.get("ok") else 0, "mysqlDatabaseTotal": int(mysql_payload.get("summary", {}).get("databaseTotal", 0)), "mysqlTableTotal": int(mysql_payload.get("summary", {}).get("tableTotal", 0)), "mysqlOk": 1 if mysql_payload.get("ok") else 0, }, "hosts": grouped_hosts, "items": service_payload["items"], "nacos": nacos_payload, "mongo": mongo_payload, "mysql": mysql_payload, }