package handlers import ( "ezops/internal/models" "net/http" "strconv" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // MetricsHandler 指标浏览器 handler // Logan.Li type MetricsHandler struct { db *gorm.DB } // NewMetricsHandler 创建指标 handler func NewMetricsHandler(db *gorm.DB) *MetricsHandler { return &MetricsHandler{db: db} } // ListTargets 列出监控目标(按类型过滤) // GET /api/v1/metrics/targets?type=host&status=online func (h *MetricsHandler) ListTargets(c *gin.Context) { var targets []models.MonitorTarget q := h.db.Model(&models.MonitorTarget{}) if t := c.Query("type"); t != "" { q = q.Where("type = ?", t) } if s := c.Query("status"); s != "" { q = q.Where("status = ?", s) } if kw := c.Query("keyword"); kw != "" { q = q.Where("name LIKE ? OR ip LIKE ?", "%"+kw+"%", "%"+kw+"%") } // 分页 page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50")) var total int64 q.Count(&total) q.Offset((page - 1) * pageSize).Limit(pageSize).Order("name ASC").Find(&targets) if targets == nil { targets = []models.MonitorTarget{} } // 附带最新指标值 type TargetWithMetrics struct { models.MonitorTarget LatestMetrics map[string]float64 `json:"latest_metrics"` } result := make([]TargetWithMetrics, len(targets)) for i, t := range targets { result[i] = TargetWithMetrics{MonitorTarget: t, LatestMetrics: make(map[string]float64)} // 查询该目标最近 10 分钟内的最新指标 var histories []models.MetricHistory h.db.Where("target_id = ? AND timestamp > ?", t.ID, now()-600). Order("timestamp DESC").Limit(10).Find(&histories) for _, mh := range histories { if _, ok := result[i].LatestMetrics[mh.MetricName]; !ok { result[i].LatestMetrics[mh.MetricName] = mh.Value } } } c.JSON(http.StatusOK, models.Response{Code: 200, Data: gin.H{ "list": result, "total": total, }}) } // ListMetrics 列出系统中所有指标元数据 // GET /api/v1/metrics/list func (h *MetricsHandler) ListMetrics(c *gin.Context) { var metrics []models.MonitorMetric h.db.Order("category ASC, name ASC").Find(&metrics) if metrics == nil { metrics = []models.MonitorMetric{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: metrics}) } // QueryValues 查询指标时序数据 // GET /api/v1/metrics/query?target_id=N&metric_name=cpu_usage&from=0&to=0&limit=100 func (h *MetricsHandler) QueryValues(c *gin.Context) { var histories []models.MetricHistory q := h.db.Model(&models.MetricHistory{}) if tid := c.Query("target_id"); tid != "" { id, _ := strconv.ParseUint(tid, 10, 64) q = q.Where("target_id = ?", id) } if mn := c.Query("metric_name"); mn != "" { q = q.Where("metric_name = ?", mn) } if from := c.Query("from"); from != "" { ts, _ := strconv.ParseInt(from, 10, 64) q = q.Where("timestamp >= ?", ts) } if to := c.Query("to"); to != "" { ts, _ := strconv.ParseInt(to, 10, 64) q = q.Where("timestamp <= ?", ts) } limit, _ := strconv.Atoi(c.DefaultQuery("limit", "200")) q.Order("timestamp ASC").Limit(limit).Find(&histories) if histories == nil { histories = []models.MetricHistory{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: histories}) } // ListMetricNames 列出所有可用的指标名称(去重) // GET /api/v1/metrics/names func (h *MetricsHandler) ListMetricNames(c *gin.Context) { var names []string h.db.Model(&models.MetricHistory{}). Distinct("metric_name"). Order("metric_name ASC"). Pluck("metric_name", &names) if names == nil { names = []string{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: names}) } func now() int64 { return time.Now().Unix() }