hy-app-monitor/monitor/dashboard.py
2026-04-22 14:39:40 +08:00

146 lines
5.1 KiB
Python

from __future__ import annotations
from typing import Any
from .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 .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()
# 组装主机维度视图。
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,
},
"hosts": grouped_hosts,
"items": service_payload["items"],
"nacos": nacos_payload,
"mongo": mongo_payload,
}