from __future__ import annotations import json from pathlib import Path from typing import Any from .env import env_float, env_int, env_int_list, env_str, load_env_file # 项目根目录。 ROOT = Path(__file__).resolve().parents[1] # 静态资源目录。 STATIC_DIR = ROOT / "static" # 默认 .env 路径。 DEFAULT_ENV_PATH = ROOT / ".env" # 先加载项目根目录的 .env。 load_env_file(Path(env_str("APP_ENV_FILE", str(DEFAULT_ENV_PATH))).expanduser()) # 监控目标配置文件路径。 CONFIG_PATH = Path(env_str("TARGETS_FILE", str(ROOT / "config" / "targets.json"))).expanduser() # HTTP 服务监听地址。 APP_BIND = env_str("APP_BIND", "0.0.0.0") or "0.0.0.0" # HTTP 服务监听端口。 APP_PORT = env_int("APP_PORT", 2026) # 服务健康检查超时时间。 PROBE_TIMEOUT_SECONDS = env_float("PROBE_TIMEOUT_SECONDS", 3.0) # 服务健康检查缓存秒数。 PROBE_CACHE_TTL_SECONDS = env_float("PROBE_CACHE_TTL_SECONDS", 5.0) # 服务健康检查并发数。 PROBE_MAX_WORKERS = env_int("PROBE_MAX_WORKERS", 12) # TAT 主机指标缓存秒数。 HOST_METRIC_CACHE_TTL_SECONDS = env_float("HOST_METRIC_CACHE_TTL_SECONDS", 25.0) # TAT 远端命令超时时间。 TAT_METRIC_TIMEOUT_SECONDS = env_int("TAT_METRIC_TIMEOUT_SECONDS", 30) # TAT CPU 采样间隔。 TAT_CPU_SAMPLE_SECONDS = env_float("TAT_CPU_SAMPLE_SECONDS", 1.0) # TAT 所在区域。 DEPLOY_REGION = env_str("DEPLOY_REGION", "me-saudi-arabia") # 腾讯云 SecretId。 TENCENT_SECRET_ID = env_str("TENCENT_SECRET_ID", "") # 腾讯云 SecretKey。 TENCENT_SECRET_KEY = env_str("TENCENT_SECRET_KEY", "") # 页面默认刷新间隔。 DEFAULT_REFRESH_INTERVAL_SECONDS = env_int("DEFAULT_REFRESH_INTERVAL_SECONDS", 10) # 页面可选刷新间隔。 REFRESH_INTERVAL_OPTIONS = env_int_list("REFRESH_INTERVAL_OPTIONS", [5, 10, 15, 30, 60]) # Nacos API 基础地址。 NACOS_BASE_URL = env_str("NACOS_BASE_URL", "http://10.2.1.17:8848").removesuffix("/nacos").rstrip("/") # Nacos 目标命名空间 ID。 NACOS_NAMESPACE_ID = env_str("NACOS_NAMESPACE_ID", "f7a8594e-090c-4830-a3ad-b5c0f9afcc07") # Nacos 目标命名空间名。 NACOS_NAMESPACE_NAME = env_str("NACOS_NAMESPACE_NAME", "RedCircleServiceProd") # Nacos 默认注册分组。 NACOS_DISCOVERY_GROUP = env_str("NACOS_DISCOVERY_GROUP", "DEFAULT_GROUP") # Nacos 默认注册集群。 NACOS_DISCOVERY_CLUSTER_NAME = env_str("NACOS_DISCOVERY_CLUSTER_NAME", "DEFAULT") # Nacos 请求超时。 NACOS_TIMEOUT_SECONDS = env_float("NACOS_TIMEOUT_SECONDS", 6.0) # Nacos 结果缓存秒数。 NACOS_CACHE_TTL_SECONDS = env_float("NACOS_CACHE_TTL_SECONDS", 15.0) # Nacos service list 单页大小。 NACOS_PAGE_SIZE = env_int("NACOS_PAGE_SIZE", 200) # Nacos 可选用户名。 NACOS_USERNAME = env_str("NACOS_USERNAME", "") # Nacos 可选密码。 NACOS_PASSWORD = env_str("NACOS_PASSWORD", "") # Mongo 连接串。 MONGO_URI = env_str("MONGO_URI", "") # Mongo 默认关注的业务库名。 MONGO_DB_NAME = env_str("MONGO_DB_NAME", "tarab_all") # Mongo 机器实例 ID,主要用于和主机指标联动显示。 MONGO_INSTANCE_ID = env_str("MONGO_INSTANCE_ID", "ins-o9mmob66") # Mongo 结果缓存秒数。 MONGO_CACHE_TTL_SECONDS = env_float("MONGO_CACHE_TTL_SECONDS", 20.0) # Mongo 建连超时。 MONGO_CONNECT_TIMEOUT_MS = env_int("MONGO_CONNECT_TIMEOUT_MS", 3000) # Mongo server selection 超时。 MONGO_SERVER_SELECTION_TIMEOUT_MS = env_int("MONGO_SERVER_SELECTION_TIMEOUT_MS", 3000) # Mongo socket 超时。 MONGO_SOCKET_TIMEOUT_MS = env_int("MONGO_SOCKET_TIMEOUT_MS", 5000) # CPU 告警阈值。 CPU_WARN_PERCENT = env_float("CPU_WARN_PERCENT", 60.0) # CPU 严重阈值。 CPU_BAD_PERCENT = env_float("CPU_BAD_PERCENT", 85.0) # 内存告警阈值。 MEMORY_WARN_PERCENT = env_float("MEMORY_WARN_PERCENT", 70.0) # 内存严重阈值。 MEMORY_BAD_PERCENT = env_float("MEMORY_BAD_PERCENT", 90.0) # 磁盘告警阈值。 DISK_WARN_PERCENT = env_float("DISK_WARN_PERCENT", 75.0) # 磁盘严重阈值。 DISK_BAD_PERCENT = env_float("DISK_BAD_PERCENT", 90.0) # 进程数告警阈值。 PROCESS_WARN_COUNT = env_int("PROCESS_WARN_COUNT", 180) # 进程数严重阈值。 PROCESS_BAD_COUNT = env_int("PROCESS_BAD_COUNT", 260) # 服务耗时告警阈值。 SERVICE_LATENCY_WARN_MS = env_int("SERVICE_LATENCY_WARN_MS", 1000) # 服务耗时严重阈值。 SERVICE_LATENCY_BAD_MS = env_int("SERVICE_LATENCY_BAD_MS", 3000) # 统一暴露给前端的阈值定义。 THRESHOLDS = { "cpuPercent": {"warn": CPU_WARN_PERCENT, "bad": CPU_BAD_PERCENT}, "memoryPercent": {"warn": MEMORY_WARN_PERCENT, "bad": MEMORY_BAD_PERCENT}, "diskPercent": {"warn": DISK_WARN_PERCENT, "bad": DISK_BAD_PERCENT}, "processCount": {"warn": PROCESS_WARN_COUNT, "bad": PROCESS_BAD_COUNT}, "latencyMs": {"warn": SERVICE_LATENCY_WARN_MS, "bad": SERVICE_LATENCY_BAD_MS}, } def utc_now() -> str: # 时间函数延迟导入,避免这里堆太多全局依赖。 from datetime import datetime, timezone # 统一输出无微秒的 UTC ISO 字符串。 return datetime.now(timezone.utc).replace(microsecond=0).isoformat() def settings_payload() -> dict[str, Any]: # 把页面需要的动态设置统一打包返回。 return { "refreshIntervalSeconds": DEFAULT_REFRESH_INTERVAL_SECONDS, "refreshIntervalOptions": list(REFRESH_INTERVAL_OPTIONS), "thresholds": THRESHOLDS, } def load_hosts() -> list[dict[str, Any]]: # 读取监控目标配置。 payload = json.loads(CONFIG_PATH.read_text(encoding="utf-8")) # 没有 hosts 时回退为空列表。 hosts = payload.get("hosts") or [] # 规范化后的主机列表。 normalized: list[dict[str, Any]] = [] # 逐台主机做结构清洗。 for host in hosts: normalized.append( { "host": str(host.get("name") or "").strip(), "group": str(host.get("group") or "").strip(), "ip": str(host.get("ip") or "").strip(), "instanceId": str(host.get("instanceId") or "").strip(), "services": host.get("services") or [], } ) # 返回可供各模块复用的主机列表。 return normalized def flatten_services(hosts: list[dict[str, Any]]) -> list[dict[str, Any]]: # 这里把主机结构拍平成服务列表,方便并发探测。 services: list[dict[str, Any]] = [] # 逐台主机展开服务。 for host in hosts: for service in host.get("services") or []: services.append( { "host": host["host"], "group": host["group"], "ip": host["ip"], "instanceId": host["instanceId"], "service": str(service.get("name") or "").strip(), "kind": str(service.get("kind") or "java").strip(), "port": int(service.get("port")), "path": str(service.get("path") or "/").strip(), } ) # 返回扁平服务列表。 return services