package handler import ( "encoding/json" "log" "net/http" "proxy-go/internal/metrics" "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 []metrics.PathMetrics `json:"top_paths"` RecentRequests []metrics.RequestLog `json:"recent_requests"` TopReferers []metrics.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 } metrics := Metrics{ Uptime: uptime.String(), ActiveRequests: stats["active_requests"].(int64), TotalRequests: stats["total_requests"].(int64), TotalErrors: stats["total_errors"].(int64), ErrorRate: float64(stats["total_errors"].(int64)) / float64(stats["total_requests"].(int64)), NumGoroutine: stats["num_goroutine"].(int), MemoryUsage: stats["memory_usage"].(string), AverageResponseTime: metrics.FormatDuration(time.Duration(stats["avg_latency"].(int64))), TotalBytes: stats["total_bytes"].(int64), BytesPerSecond: float64(stats["total_bytes"].(int64)) / metrics.Max(uptime.Seconds(), 1), RequestsPerSecond: float64(stats["total_requests"].(int64)) / metrics.Max(uptime.Seconds(), 1), StatusCodeStats: stats["status_code_stats"].(map[string]int64), TopPaths: stats["top_paths"].([]metrics.PathMetrics), RecentRequests: stats["recent_requests"].([]metrics.RequestLog), TopReferers: stats["top_referers"].([]metrics.PathMetrics), } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(metrics); err != nil { log.Printf("Error encoding metrics: %v", err) } } // 修改模板,添加登录页面 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, }) }