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
`
// 修改原有的 metricsTemplate,添加 token 检查
var metricsTemplate = `
Proxy-Go Metrics
Proxy-Go Metrics
基础指标
运行时间
当前活跃请求
总请求数
错误数
错误率
历史数据
`
// 添加认证中间件
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{}
}