package main import ( "fmt" "net" "strings" "time" ) // LatencyInfo 延迟信息(均由采集端在本机测量) type LatencyInfo struct { ClientToServer float64 `json:"clientToServer"` // 采集器 → 监控中心 gRPC 地址的 TCP 建连耗时(ms),失败为 -1 External map[string]string `json:"external"` // 采集器对外站点的 TCP 建连耗时(同 checkExternalLatency) } // normalizeGRPCDialTarget strips common grpc-go target prefixes; expects host:port or [ipv6]:port. func normalizeGRPCDialTarget(addr string) string { a := strings.TrimSpace(addr) a = strings.TrimPrefix(a, "dns:///") a = strings.TrimPrefix(a, "dns://") return strings.TrimSpace(a) } // measureCollectorToCentralTCP returns TCP connect time in ms to the central gRPC dial target, or -1 on failure. func measureCollectorToCentralTCP(grpcAddr string, timeout time.Duration) float64 { target := normalizeGRPCDialTarget(grpcAddr) if target == "" || strings.HasPrefix(strings.ToLower(target), "unix:") { return -1 } start := time.Now() conn, err := net.DialTimeout("tcp", target, timeout) if err != nil { return -1 } _ = conn.Close() return float64(time.Since(start).Microseconds()) / 1000.0 } // checkExternalLatency 检测外部网站延迟 func checkExternalLatency(host string, timeout time.Duration) string { start := time.Now() // 尝试 TCP 连接 80 端口 conn, err := net.DialTimeout("tcp", host+":80", timeout) if err != nil { // 如果 80 端口失败,尝试 443 (HTTPS) conn, err = net.DialTimeout("tcp", host+":443", timeout) if err != nil { return "超时" } } defer conn.Close() // 使用微秒换算,避免 Milliseconds() 截断成 0 ms 误导用户 ms := float64(time.Since(start).Microseconds()) / 1000.0 if ms < 1 { return fmt.Sprintf("%.1f ms", ms) } return fmt.Sprintf("%.0f ms", ms) } // readExternalLatencies 读取外部网站延迟 func readExternalLatencies() map[string]string { latencies := make(map[string]string) timeout := 3 * time.Second // 检测百度 latencies["baidu.com"] = checkExternalLatency("baidu.com", timeout) // 检测谷歌 latencies["google.com"] = checkExternalLatency("google.com", timeout) // 检测 GitHub latencies["github.com"] = checkExternalLatency("github.com", timeout) return latencies }