package monitor import ( "net/http" "sort" "strconv" "time" "github.com/gin-gonic/gin" ) // APIMonitorController API 监控控制器 type APIMonitorController struct{} // NewAPIMonitorController 创建 API 监控控制器 func NewAPIMonitorController() *APIMonitorController { return &APIMonitorController{} } // GetAPIStats 获取指定 API 的统计信息 func (amc *APIMonitorController) GetAPIStats(c *gin.Context) { endpoint := c.Query("endpoint") if endpoint == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "缺少 endpoint 参数", }) return } apiMonitorsMu.RLock() monitor, exists := apiMonitors[endpoint] apiMonitorsMu.RUnlock() if !exists { c.JSON(http.StatusNotFound, gin.H{ "error": "该接口暂无监控数据", }) return } stats := monitor.GetStats() c.JSON(http.StatusOK, gin.H{ "status": "success", "data": stats, "timestamp": time.Now().Format("2006-01-02 15:04:05"), }) } // GetAllAPIStats 获取所有 API 的统计信息 func (amc *APIMonitorController) GetAllAPIStats(c *gin.Context) { apiMonitorsMu.RLock() defer apiMonitorsMu.RUnlock() allStats := make([]*APIStats, 0, len(apiMonitors)) endpoints := make([]string, 0, len(apiMonitors)) // 收集所有 endpoint for endpoint := range apiMonitors { endpoints = append(endpoints, endpoint) } // 按 endpoint 字母顺序排序 sort.Strings(endpoints) // 按排序后的顺序获取统计信息 for _, endpoint := range endpoints { allStats = append(allStats, apiMonitors[endpoint].GetStats()) } c.JSON(http.StatusOK, gin.H{ "status": "success", "data": allStats, "count": len(allStats), "timestamp": time.Now().Format("2006-01-02 15:04:05"), }) } // GetAPICallDetail 获取指定 API 调用的详细信息 func (amc *APIMonitorController) GetAPICallDetail(c *gin.Context) { endpoint := c.Query("endpoint") callIDStr := c.Query("call_id") callType := c.Query("type") // es or redis if endpoint == "" || callIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "缺少 endpoint 或 call_id 参数", }) return } callID, err := strconv.ParseInt(callIDStr, 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "无效的 call_id", }) return } apiMonitorsMu.RLock() monitor, exists := apiMonitors[endpoint] apiMonitorsMu.RUnlock() if !exists { c.JSON(http.StatusNotFound, gin.H{ "error": "该接口暂无监控数据", }) return } // 查找对应的调用记录 var foundRecord *APICallRecord var recordType string if callType == "es" { foundRecord = monitor.GetESCallByID(callID) if foundRecord != nil { recordType = "ES" } } else if callType == "redis" { foundRecord = monitor.GetRedisCallByID(callID) if foundRecord != nil { recordType = "Redis" } } else { c.JSON(http.StatusBadRequest, gin.H{ "error": "type 参数必须是 es 或 redis", }) return } if foundRecord == nil { c.JSON(http.StatusNotFound, gin.H{ "error": "未找到对应的调用记录", }) return } c.JSON(http.StatusOK, gin.H{ "status": "success", "data": gin.H{ "id": foundRecord.ID, "type": recordType, "timestamp": foundRecord.Timestamp.Format("2006-01-02 15:04:05"), "duration_ms": foundRecord.Duration, "success": foundRecord.Success, "error": foundRecord.Error, "operation": foundRecord.Operation, "key_or_index": foundRecord.KeyOrIndex, "query": foundRecord.Query, "request": foundRecord.Request, "response": foundRecord.Response, }, }) } // GetAPIESCalls 获取指定 API 的 ES 调用记录 func (amc *APIMonitorController) GetAPIESCalls(c *gin.Context) { endpoint := c.Query("endpoint") if endpoint == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "缺少 endpoint 参数", }) return } pageStr := c.DefaultQuery("page", "1") pageSizeStr := c.DefaultQuery("page_size", "50") page, err := strconv.Atoi(pageStr) if err != nil || page <= 0 { page = 1 } pageSize, err := strconv.Atoi(pageSizeStr) if err != nil || pageSize <= 0 { pageSize = 50 } if pageSize > 500 { pageSize = 500 } apiMonitorsMu.RLock() monitor, exists := apiMonitors[endpoint] apiMonitorsMu.RUnlock() if !exists { c.JSON(http.StatusNotFound, gin.H{ "error": "该接口暂无监控数据", }) return } calls, total := monitor.GetRecentESCalls(page, pageSize) totalPages := (total + pageSize - 1) / pageSize c.JSON(http.StatusOK, gin.H{ "status": "success", "data": gin.H{ "calls": calls, "count": len(calls), "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages, }, "timestamp": time.Now().Format("2006-01-02 15:04:05"), }) } // GetAPIRedisCalls 获取指定 API 的 Redis 调用记录 func (amc *APIMonitorController) GetAPIRedisCalls(c *gin.Context) { endpoint := c.Query("endpoint") if endpoint == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "缺少 endpoint 参数", }) return } pageStr := c.DefaultQuery("page", "1") pageSizeStr := c.DefaultQuery("page_size", "50") page, err := strconv.Atoi(pageStr) if err != nil || page <= 0 { page = 1 } pageSize, err := strconv.Atoi(pageSizeStr) if err != nil || pageSize <= 0 { pageSize = 50 } if pageSize > 500 { pageSize = 500 } apiMonitorsMu.RLock() monitor, exists := apiMonitors[endpoint] apiMonitorsMu.RUnlock() if !exists { c.JSON(http.StatusNotFound, gin.H{ "error": "该接口暂无监控数据", }) return } calls, total := monitor.GetRecentRedisCalls(page, pageSize) totalPages := (total + pageSize - 1) / pageSize c.JSON(http.StatusOK, gin.H{ "status": "success", "data": gin.H{ "calls": calls, "count": len(calls), "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages, }, "timestamp": time.Now().Format("2006-01-02 15:04:05"), }) } // GetAPIMonitorDashboard 获取 API 监控仪表板 func (amc *APIMonitorController) GetAPIMonitorDashboard(c *gin.Context) { dashboardHTML := ` API 监控仪表板

🔍 API 监控仪表板 - ES & Redis 调用

所有接口概览

详细监控数据

` c.Header("Content-Type", "text/html; charset=utf-8") c.String(http.StatusOK, dashboardHTML) }