package handler import ( "encoding/json" "log" "net/http" "proxy-go/internal/metrics" "proxy-go/internal/models" "strconv" "strings" "time" ) type Metrics struct { // 基础指标 Uptime string `json:"uptime"` ActiveRequests int64 `json:"active_requests"` TotalRequests int64 `json:"total_requests"` TotalErrors int64 `json:"total_errors"` ErrorRate float64 `json:"error_rate"` // 系统指标 NumGoroutine int `json:"num_goroutine"` MemoryUsage string `json:"memory_usage"` // 性能指标 AverageResponseTime string `json:"avg_response_time"` RequestsPerSecond float64 `json:"requests_per_second"` // 新增字段 TotalBytes int64 `json:"total_bytes"` BytesPerSecond float64 `json:"bytes_per_second"` StatusCodeStats map[string]int64 `json:"status_code_stats"` LatencyPercentiles map[string]float64 `json:"latency_percentiles"` TopPaths []models.PathMetrics `json:"top_paths"` RecentRequests []models.RequestLog `json:"recent_requests"` TopReferers []models.PathMetrics `json:"top_referers"` } func (h *ProxyHandler) MetricsHandler(w http.ResponseWriter, r *http.Request) { uptime := time.Since(h.startTime) collector := metrics.GetCollector() stats := collector.GetStats() if stats == nil { http.Error(w, "Failed to get metrics", http.StatusInternalServerError) return } // 添加安全的类型转换函数 safeInt64 := func(v interface{}) int64 { if v == nil { return 0 } if i, ok := v.(int64); ok { return i } return 0 } safeInt := func(v interface{}) int { if v == nil { return 0 } if i, ok := v.(int); ok { return i } return 0 } // 添加安全的字符串转换函数 safeString := func(v interface{}) string { if v == nil { return "0 B" // 返回默认值 } if s, ok := v.(string); ok { return s } return "0 B" // 返回默认值 } totalRequests := safeInt64(stats["total_requests"]) metrics := Metrics{ Uptime: uptime.String(), ActiveRequests: safeInt64(stats["active_requests"]), TotalRequests: totalRequests, TotalErrors: safeInt64(stats["total_errors"]), ErrorRate: float64(safeInt64(stats["total_errors"])) / float64(max(totalRequests, 1)), NumGoroutine: safeInt(stats["num_goroutine"]), MemoryUsage: safeString(stats["memory_usage"]), // 使用安全转换 AverageResponseTime: metrics.FormatDuration(time.Duration(safeInt64(stats["avg_latency"]))), TotalBytes: safeInt64(stats["total_bytes"]), BytesPerSecond: float64(safeInt64(stats["total_bytes"])) / metrics.Max(uptime.Seconds(), 1), RequestsPerSecond: float64(totalRequests) / metrics.Max(uptime.Seconds(), 1), StatusCodeStats: safeStatusCodeStats(stats["status_code_stats"]), // 添加安全转换 TopPaths: safePathMetrics(stats["top_paths"]), // 添加安全转换 RecentRequests: safeRequestLogs(stats["recent_requests"]), // 添加安全转换 TopReferers: safePathMetrics(stats["top_referers"]), // 添加安全转换 } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(metrics); err != nil { log.Printf("Error encoding metrics: %v", err) } } // 辅助函数 func max(a, b int64) int64 { if a > b { return a } return b } // 修改模板,添加登录页面 var loginTemplate = ` Proxy-Go Metrics Login

Metrics Login

密码错误
` // 修改原有的 metricsTemplate,添加 token 检查 var metricsTemplate = ` Proxy-Go Metrics

Proxy-Go Metrics

基础指标

运行时间
当前活跃请求
总请求数
错误数
错误率

系统指标

Goroutine数量
内存使用

性能指标

平均响应时间
每秒请求数

流量统计

总传输字节
每秒传输

状态码统计

热门路径 (Top 10)

路径 请求数 错误数 平均延迟 传输大小

最近请求

时间 路径 状态 延迟 大小 客户端IP

热门引用来源 (Top 10)

来源 请求数

历史数据

` // 添加认证中间件 func (h *ProxyHandler) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { auth := r.Header.Get("Authorization") if auth == "" || !strings.HasPrefix(auth, "Bearer ") { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } token := strings.TrimPrefix(auth, "Bearer ") if !h.auth.validateToken(token) { http.Error(w, "Invalid token", http.StatusUnauthorized) return } next(w, r) } } // 修改处理器 func (h *ProxyHandler) MetricsPageHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(loginTemplate)) } func (h *ProxyHandler) MetricsDashboardHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(metricsTemplate)) } func (h *ProxyHandler) MetricsAuthHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { Password string `json:"password"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return } if req.Password != h.config.Metrics.Password { http.Error(w, "Invalid password", http.StatusUnauthorized) return } token := h.auth.generateToken() h.auth.addToken(token, time.Duration(h.config.Metrics.TokenExpiry)*time.Second) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "token": token, }) } // 添加历史数据查询接口 func (h *ProxyHandler) MetricsHistoryHandler(w http.ResponseWriter, r *http.Request) { hours := 24 // 默认24小时 if h := r.URL.Query().Get("hours"); h != "" { if parsed, err := strconv.Atoi(h); err == nil && parsed > 0 { hours = parsed } } collector := metrics.GetCollector() metrics, err := collector.GetDB().GetRecentMetrics(hours) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(metrics) } // 添加安全的类型转换辅助函数 func safeStatusCodeStats(v interface{}) map[string]int64 { if v == nil { return make(map[string]int64) } if m, ok := v.(map[string]int64); ok { return m } return make(map[string]int64) } func safePathMetrics(v interface{}) []models.PathMetrics { if v == nil { return []models.PathMetrics{} } if m, ok := v.([]models.PathMetrics); ok { return m } return []models.PathMetrics{} } func safeRequestLogs(v interface{}) []models.RequestLog { if v == nil { return []models.RequestLog{} } if m, ok := v.([]models.RequestLog); ok { return m } return []models.RequestLog{} }