移除服务监控对探针标签功能的支持
This commit is contained in:
1 parent
183058a754
commit
77d06f19cf
4 files changed
+142
-100
No files matched your search
@@ -202,7 +202,7 @@ func (h *MonitorHandler) GetHistoryByID(c echo.Context) error {
|
||||
return orz.NewError(400, err.Error())
|
||||
}
|
||||
|
||||
history, err := h.monitorService.GetMonitorHistory(ctx, id, start, end, aggregation)
|
||||
history, err := h.metricService.GetMonitorHistory(ctx, id, start, end, aggregation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ type MonitorTask struct {
|
||||
Interval int `json:"interval"` // 检测频率(秒),默认 60
|
||||
AgentIds datatypes.JSONSlice[string] `json:"agentIds"` // 指定的探针 ID 列表(JSON 数组)
|
||||
AgentNames []string `gorm:"-" json:"agentNames"` // 指定的探针名称列表
|
||||
Tags datatypes.JSONSlice[string] `json:"tags"` // 指定的标签列表(JSON 数组),拥有这些标签的探针都会执行此监控
|
||||
HTTPConfig datatypes.JSONType[protocol.HTTPMonitorConfig] `json:"httpConfig"` // HTTP 监控配置
|
||||
TCPConfig datatypes.JSONType[protocol.TCPMonitorConfig] `json:"tcpConfig"` // TCP 监控配置
|
||||
ICMPConfig datatypes.JSONType[protocol.ICMPMonitorConfig] `json:"icmpConfig"` // ICMP 监控配置
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -296,6 +297,38 @@ func (s *MetricService) GetMetrics(ctx context.Context, agentID, metricType stri
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CleanMonitorCache 清理监控任务缓存中不再关联的探针数据
|
||||
func (s *MetricService) CleanMonitorCache(ctx context.Context, monitorID string) error {
|
||||
// 从缓存读取监控数据
|
||||
latestMetrics, ok := s.monitorLatestCache.Get(monitorID)
|
||||
if !ok {
|
||||
// 缓存不存在,无需清理
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查询监控任务配置
|
||||
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 只在有过滤条件(指定了 AgentIds)时清理缓存
|
||||
if len(monitorTask.AgentIds) > 0 {
|
||||
// 遍历缓存中的探针,移除不再关联的探针数据
|
||||
for agentId := range latestMetrics.Agents.Keys() {
|
||||
if !slices.Contains(monitorTask.AgentIds, agentId) {
|
||||
// 该探针已不再关联到此监控任务,从缓存中移除
|
||||
latestMetrics.Agents.Delete(agentId)
|
||||
s.logger.Debug("从监控缓存中移除探针",
|
||||
zap.String("monitorID", monitorID),
|
||||
zap.String("agentID", agentId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateMonitorCache 更新监控数据缓存
|
||||
func (s *MetricService) updateMonitorCache(agentID string, monitorData *protocol.MonitorData, timestamp int64) {
|
||||
monitorID := monitorData.MonitorId
|
||||
@@ -572,6 +605,13 @@ func (s *MetricService) buildMonitorPromQLQueries(monitorID string, aggregation
|
||||
|
||||
// GetMonitorHistory 获取监控任务的历史趋势数据
|
||||
func (s *MetricService) GetMonitorHistory(ctx context.Context, monitorID string, start, end int64, aggregation string) (*metric.GetMetricsResponse, error) {
|
||||
// 查询监控任务配置
|
||||
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
|
||||
if err != nil {
|
||||
s.logger.Error("查询监控任务失败", zap.String("monitorID", monitorID), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
step := vmclient.AutoStep(time.UnixMilli(start), time.UnixMilli(end))
|
||||
queries := s.buildMonitorPromQLQueries(monitorID, aggregation, step)
|
||||
|
||||
@@ -592,11 +632,26 @@ func (s *MetricService) GetMonitorHistory(ctx context.Context, monitorID string,
|
||||
series = append(series, convertedSeries...)
|
||||
}
|
||||
|
||||
// 收集所有 agent_id
|
||||
// 过滤掉已取消关联的 agent 数据(仅在有过滤条件时)
|
||||
agentIdSet := make(map[string]struct{})
|
||||
for _, s := range series {
|
||||
if agentId, ok := s.Labels["agent_id"]; ok {
|
||||
agentIdSet[agentId] = struct{}{}
|
||||
if len(monitorTask.AgentIds) > 0 {
|
||||
// 有过滤条件,只保留当前关联的 agent 数据
|
||||
filteredSeries := make([]metric.Series, 0)
|
||||
for _, s := range series {
|
||||
if agentId, ok := s.Labels["agent_id"]; ok {
|
||||
if slices.Contains(monitorTask.AgentIds, agentId) {
|
||||
filteredSeries = append(filteredSeries, s)
|
||||
agentIdSet[agentId] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
series = filteredSeries
|
||||
} else {
|
||||
// 无过滤条件,收集所有 agent_id
|
||||
for _, s := range series {
|
||||
if agentId, ok := s.Labels["agent_id"]; ok {
|
||||
agentIdSet[agentId] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,14 +700,31 @@ func (s *MetricService) GetMonitorAgentStats(monitorID string) []protocol.Monito
|
||||
return []protocol.MonitorData{}
|
||||
}
|
||||
|
||||
// 收集所有 agentId
|
||||
agentIds := make([]string, 0, latestMetrics.Agents.Len())
|
||||
for agentId := range latestMetrics.Agents.Keys() {
|
||||
agentIds = append(agentIds, agentId)
|
||||
// 查询监控任务配置
|
||||
ctx := context.Background()
|
||||
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
|
||||
if err != nil {
|
||||
s.logger.Error("查询监控任务失败", zap.String("monitorID", monitorID), zap.Error(err))
|
||||
return []protocol.MonitorData{}
|
||||
}
|
||||
|
||||
// 收集所有当前关联的 agentId(从缓存中过滤)
|
||||
agentIds := make([]string, 0)
|
||||
if len(monitorTask.AgentIds) > 0 {
|
||||
// 有过滤条件,只保留匹配的 agent
|
||||
for agentId := range latestMetrics.Agents.Keys() {
|
||||
if slices.Contains(monitorTask.AgentIds, agentId) {
|
||||
agentIds = append(agentIds, agentId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 无过滤条件,返回所有缓存中的 agent
|
||||
for agentId := range latestMetrics.Agents.Keys() {
|
||||
agentIds = append(agentIds, agentId)
|
||||
}
|
||||
}
|
||||
|
||||
// 查询 agent 信息
|
||||
ctx := context.Background()
|
||||
agents, err := s.agentRepo.FindByIdIn(ctx, agentIds)
|
||||
if err != nil {
|
||||
s.logger.Error("查询 agent 信息失败", zap.Error(err))
|
||||
@@ -665,10 +737,20 @@ func (s *MetricService) GetMonitorAgentStats(monitorID string) []protocol.Monito
|
||||
}
|
||||
|
||||
// 转换为数组并填充 agent 名称
|
||||
result := make([]protocol.MonitorData, 0, latestMetrics.Agents.Len())
|
||||
result := make([]protocol.MonitorData, 0, len(agentIds))
|
||||
for stat := range latestMetrics.Agents.Values() {
|
||||
stat.AgentName = agentNameMap[stat.AgentId] // 填充 agent 名称
|
||||
result = append(result, *stat)
|
||||
// 根据过滤条件决定是否包含该 agent
|
||||
if len(monitorTask.AgentIds) > 0 {
|
||||
// 有过滤条件,只返回当前关联的 agent 数据
|
||||
if slices.Contains(monitorTask.AgentIds, stat.AgentId) {
|
||||
stat.AgentName = agentNameMap[stat.AgentId] // 填充 agent 名称
|
||||
result = append(result, *stat)
|
||||
}
|
||||
} else {
|
||||
// 无过滤条件,返回所有 agent 数据
|
||||
stat.AgentName = agentNameMap[stat.AgentId] // 填充 agent 名称
|
||||
result = append(result, *stat)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -685,12 +767,22 @@ func (s *MetricService) GetMonitorStats(monitorID string) *metric.MonitorStatsRe
|
||||
}
|
||||
}
|
||||
|
||||
// 查询监控任务配置
|
||||
ctx := context.Background()
|
||||
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
|
||||
if err != nil {
|
||||
s.logger.Error("查询监控任务失败", zap.String("monitorID", monitorID), zap.Error(err))
|
||||
return &metric.MonitorStatsResult{
|
||||
Status: "unknown",
|
||||
}
|
||||
}
|
||||
|
||||
// 聚合各探针数据
|
||||
return s.aggregateMonitorStats(latestMetrics)
|
||||
return s.aggregateMonitorStats(latestMetrics, monitorTask.AgentIds)
|
||||
}
|
||||
|
||||
// aggregateMonitorStats 聚合各探针的监控数据
|
||||
func (s *MetricService) aggregateMonitorStats(latestMetrics *metric.LatestMonitorMetrics) *metric.MonitorStatsResult {
|
||||
func (s *MetricService) aggregateMonitorStats(latestMetrics *metric.LatestMonitorMetrics, agentIds []string) *metric.MonitorStatsResult {
|
||||
result := &metric.MonitorStatsResult{
|
||||
Status: "unknown",
|
||||
}
|
||||
@@ -704,11 +796,21 @@ func (s *MetricService) aggregateMonitorStats(latestMetrics *metric.LatestMonito
|
||||
var maxResponseTime int64
|
||||
var lastCheckTime int64
|
||||
var upCount, downCount, unknownCount int
|
||||
var validCount int // 实际聚合的探针数量
|
||||
hasCert := false
|
||||
var minCertExpiryTime int64
|
||||
var minCertDaysLeft int
|
||||
|
||||
for stat := range latestMetrics.Agents.Values() {
|
||||
// 根据过滤条件决定是否聚合该探针
|
||||
if len(agentIds) > 0 {
|
||||
// 有过滤条件,只聚合当前关联的探针数据
|
||||
if !slices.Contains(agentIds, stat.AgentId) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
validCount++
|
||||
totalResponseTime += stat.ResponseTime
|
||||
|
||||
// 计算响应时间的最小值和最大值
|
||||
@@ -742,10 +844,9 @@ func (s *MetricService) aggregateMonitorStats(latestMetrics *metric.LatestMonito
|
||||
}
|
||||
}
|
||||
|
||||
count := latestMetrics.Agents.Len()
|
||||
result.AgentCount = count
|
||||
if count > 0 {
|
||||
result.ResponseTime = totalResponseTime / int64(count)
|
||||
result.AgentCount = validCount
|
||||
if validCount > 0 {
|
||||
result.ResponseTime = totalResponseTime / int64(validCount)
|
||||
}
|
||||
result.ResponseTimeMin = minResponseTime
|
||||
result.ResponseTimeMax = maxResponseTime
|
||||
|
||||
@@ -68,7 +68,6 @@ type MonitorTaskRequest struct {
|
||||
TCPConfig protocol.TCPMonitorConfig `json:"tcpConfig,omitempty"`
|
||||
ICMPConfig protocol.ICMPMonitorConfig `json:"icmpConfig,omitempty"`
|
||||
AgentIds []string `json:"agentIds,omitempty"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
func (s *MonitorService) CreateMonitor(ctx context.Context, req *MonitorTaskRequest) (*models.MonitorTask, error) {
|
||||
@@ -95,7 +94,6 @@ func (s *MonitorService) CreateMonitor(ctx context.Context, req *MonitorTaskRequ
|
||||
Visibility: visibility,
|
||||
Interval: interval,
|
||||
AgentIds: datatypes.JSONSlice[string](req.AgentIds),
|
||||
Tags: datatypes.JSONSlice[string](req.Tags),
|
||||
HTTPConfig: datatypes.NewJSONType(req.HTTPConfig),
|
||||
TCPConfig: datatypes.NewJSONType(req.TCPConfig),
|
||||
ICMPConfig: datatypes.NewJSONType(req.ICMPConfig),
|
||||
@@ -136,7 +134,6 @@ func (s *MonitorService) UpdateMonitor(ctx context.Context, id string, req *Moni
|
||||
task.Description = req.Description
|
||||
task.ShowTargetPublic = req.ShowTargetPublic
|
||||
task.Visibility = req.Visibility
|
||||
task.Tags = req.Tags
|
||||
|
||||
// 更新检测频率
|
||||
interval := req.Interval
|
||||
@@ -154,6 +151,16 @@ func (s *MonitorService) UpdateMonitor(ctx context.Context, id string, req *Moni
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 清理监控缓存中不再关联的探针数据
|
||||
if s.metricService != nil {
|
||||
if err := s.metricService.CleanMonitorCache(ctx, id); err != nil {
|
||||
s.logger.Warn("清理监控缓存失败",
|
||||
zap.String("monitorID", id),
|
||||
zap.Error(err))
|
||||
// 不返回错误,继续执行
|
||||
}
|
||||
}
|
||||
|
||||
// 更新调度器
|
||||
if s.scheduler != nil {
|
||||
// 如果从禁用变为启用,或者间隔时间改变
|
||||
@@ -255,57 +262,6 @@ func (s *MonitorService) buildMonitorOverview(monitor models.MonitorTask, stats
|
||||
return overview
|
||||
}
|
||||
|
||||
// resolveTargetAgents 计算监控任务对应的目标探针范围
|
||||
// 规则:
|
||||
// 1. 如果既没有指定 AgentIds 也没有指定 Tags,返回所有传入的探针(全部节点)
|
||||
// 2. 如果指定了 AgentIds 或 Tags(或两者都指定),则返回匹配的探针(自动去重)
|
||||
// - AgentIds: 直接匹配探针 ID
|
||||
// - Tags: 匹配探针标签中包含任意一个指定标签的探针
|
||||
// - 两者结果取并集
|
||||
func (s *MonitorService) resolveTargetAgents(monitor models.MonitorTask, availableAgents []models.Agent) []models.Agent {
|
||||
// 如果既没有指定 AgentIds 也没有指定 Tags,使用所有可用探针
|
||||
if len(monitor.AgentIds) == 0 && len(monitor.Tags) == 0 {
|
||||
return availableAgents
|
||||
}
|
||||
|
||||
// 使用 map 来去重
|
||||
targetAgentIDSet := make(map[string]struct{})
|
||||
|
||||
// 1. 处理通过 AgentIds 指定的探针
|
||||
if len(monitor.AgentIds) > 0 {
|
||||
for _, agentID := range monitor.AgentIds {
|
||||
targetAgentIDSet[agentID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理通过 Tags 指定的探针
|
||||
if len(monitor.Tags) > 0 {
|
||||
for _, agent := range availableAgents {
|
||||
if agent.Tags != nil && len(agent.Tags) > 0 {
|
||||
// 检查探针的标签中是否包含任何一个指定的标签
|
||||
for _, agentTag := range agent.Tags {
|
||||
for _, monitorTag := range monitor.Tags {
|
||||
if agentTag == monitorTag {
|
||||
targetAgentIDSet[agent.ID] = struct{}{}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 根据去重后的 ID 集合筛选探针
|
||||
targetAgents := make([]models.Agent, 0, len(targetAgentIDSet))
|
||||
for _, agent := range availableAgents {
|
||||
if _, ok := targetAgentIDSet[agent.ID]; ok {
|
||||
targetAgents = append(targetAgents, agent)
|
||||
}
|
||||
}
|
||||
|
||||
return targetAgents
|
||||
}
|
||||
|
||||
// sendMonitorConfigToAgent 向指定探针发送监控配置(内部方法)
|
||||
func (s *MonitorService) sendMonitorConfigToAgent(agentID string, payload protocol.MonitorConfigPayload) error {
|
||||
msgData, err := json.Marshal(protocol.OutboundMessage{
|
||||
@@ -321,25 +277,17 @@ func (s *MonitorService) sendMonitorConfigToAgent(agentID string, payload protoc
|
||||
|
||||
// SendMonitorTaskToAgents 向指定探针发送单个监控任务(公开方法)
|
||||
func (s *MonitorService) SendMonitorTaskToAgents(ctx context.Context, monitor models.MonitorTask) error {
|
||||
// 实时获取所有在线探针,避免依赖数据库状态
|
||||
onlineIDs := s.wsManager.GetAllClients()
|
||||
if len(onlineIDs) == 0 {
|
||||
return nil
|
||||
// 确定目标探针 ID 列表
|
||||
var targetAgentIDs []string
|
||||
if len(monitor.AgentIds) == 0 {
|
||||
// 没有指定探针,向所有在线探针发送
|
||||
targetAgentIDs = s.wsManager.GetAllClients()
|
||||
} else {
|
||||
// 指定了探针
|
||||
targetAgentIDs = monitor.AgentIds
|
||||
}
|
||||
|
||||
// 查询在线探针的详细信息
|
||||
onlineAgents, err := s.agentRepo.ListByIDs(ctx, onlineIDs)
|
||||
if err != nil {
|
||||
s.logger.Error("获取在线探针信息失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if len(onlineAgents) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 使用统一的方法计算目标探针
|
||||
targetAgents := s.resolveTargetAgents(monitor, onlineAgents)
|
||||
if len(targetAgents) == 0 {
|
||||
if len(targetAgentIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -368,12 +316,12 @@ func (s *MonitorService) SendMonitorTaskToAgents(ctx context.Context, monitor mo
|
||||
}
|
||||
|
||||
// 向每个目标探针发送
|
||||
for _, agent := range targetAgents {
|
||||
if err := s.sendMonitorConfigToAgent(agent.ID, payload); err != nil {
|
||||
for _, agentID := range targetAgentIDs {
|
||||
if err := s.sendMonitorConfigToAgent(agentID, payload); err != nil {
|
||||
s.logger.Error("发送监控配置失败",
|
||||
zap.String("taskID", monitor.ID),
|
||||
zap.String("taskName", monitor.Name),
|
||||
zap.String("agentID", agent.ID),
|
||||
zap.String("agentID", agentID),
|
||||
zap.Error(err))
|
||||
}
|
||||
}
|
||||
@@ -397,12 +345,6 @@ func (s *MonitorService) GetMonitorStatsByID(ctx context.Context, monitorID stri
|
||||
return &overview, nil
|
||||
}
|
||||
|
||||
// GetMonitorHistory 获取监控任务的历史时序数据
|
||||
// 直接返回 VictoriaMetrics 的原始时序数据,包含所有探针的独立序列
|
||||
func (s *MonitorService) GetMonitorHistory(ctx context.Context, monitorID string, start, end int64, aggregation string) (*metric.GetMetricsResponse, error) {
|
||||
return s.metricService.GetMonitorHistory(ctx, monitorID, start, end, aggregation)
|
||||
}
|
||||
|
||||
// GetMonitorByAuth 根据认证状态获取监控任务(已登录返回全部,未登录返回公开可见)
|
||||
func (s *MonitorService) GetMonitorByAuth(ctx context.Context, id string, isAuthenticated bool) (*models.MonitorTask, error) {
|
||||
if isAuthenticated {
|
||||
|
||||
Reference in new issue
Block a user