优化服务监控的数据查询逻辑

This commit is contained in:
dushixiang committed 2025-11-23 19:40:08 +08:00
1 parent c4575e976c
commit 76355e57c6
8 files changed
+63 -126

No files matched your search

+33 -23
View File
@@ -11,43 +11,26 @@ import (
type MonitorHandler struct {
logger *zap.Logger
monitorService *service.MonitorService
agentService *service.AgentService
}
func NewMonitorHandler(logger *zap.Logger, monitorService *service.MonitorService) *MonitorHandler {
func NewMonitorHandler(logger *zap.Logger, monitorService *service.MonitorService, agentService *service.AgentService) *MonitorHandler {
return &MonitorHandler{
logger: logger,
monitorService: monitorService,
agentService: agentService,
}
}
func (h *MonitorHandler) List(c echo.Context) error {
keyword := c.QueryParam("keyword")
name := c.QueryParam("name")
target := c.QueryParam("target")
typeParam := c.QueryParam("type")
enabled := c.QueryParam("enabled")
pr := orz.GetPageRequest(c, "-updated_at", "name")
pr := orz.GetPageRequest(c, "name")
builder := orz.NewPageBuilder(h.monitorService.MonitorRepo).
PageRequest(pr)
// 如果有 keyword,则搜索 name(也可以搜索 target)
if keyword != "" {
// keyword 可以匹配 name 或 target
builder.Contains("name", keyword)
// 如果需要同时搜索 target,可以手动构建 OR 查询
// 这里简化处理,只搜索 name
} else {
// 否则使用独立的 name 和 target 搜索
builder.Contains("name", name).
Contains("target", target)
}
// 处理类型筛选
if typeParam != "" {
builder.Equal("type", typeParam)
}
PageRequest(pr).
Keyword([]string{"name", "target", "type"}, keyword)
// 处理启用状态筛选
if enabled == "true" {
@@ -61,6 +44,33 @@ func (h *MonitorHandler) List(c echo.Context) error {
if err != nil {
return err
}
var agentIds []string
for _, item := range page.Items {
if len(item.AgentIds) > 0 {
agentIds = append(agentIds, item.AgentIds...)
}
}
if len(agentIds) > 0 {
agents, err := h.agentService.AgentRepo.FindByIdIn(ctx, agentIds)
if err != nil {
return err
}
var agentNameMap = make(map[string]string)
for _, agent := range agents {
agentNameMap[agent.ID] = agent.Name
}
for i, monitor := range page.Items {
if len(monitor.AgentIds) == 0 {
continue
}
for _, agentId := range monitor.AgentIds {
page.Items[i].AgentNames = append(page.Items[i].AgentNames, agentNameMap[agentId])
}
}
}
return orz.Ok(c, page)
}
-1
View File
@@ -9,7 +9,6 @@ type MonitorStats struct {
MonitorName string `gorm:"-" json:"name"` // 监控项名称(不存储在数据库,仅用于 API 返回)
MonitorType string `json:"type"` // 监控类型
Target string `json:"target"` // 目标地址
ShowTargetPublic bool `gorm:"-" json:"showTargetPublic"` // 在公开页面是否显示目标地址(不存储在数据库,仅用于 API 返回)
CurrentResponse int64 `json:"currentResponse"` // 当前响应时间(ms)
AvgResponse24h int64 `json:"avgResponse24h"` // 24小时平均响应时间(ms)
Uptime24h float64 `json:"uptime24h"` // 24小时在线率(百分比)
+1
View File
@@ -17,6 +17,7 @@ type MonitorTask struct {
Visibility string `gorm:"default:public" json:"visibility"` // 可见性: public-匿名可见, private-登录可见
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 监控配置
+24 -97
View File
@@ -378,93 +378,6 @@ func (s *MonitorService) resolveTargetAgents(monitor models.MonitorTask, availab
return targetAgents
}
// BroadcastMonitorConfig 向所有在线探针广播监控配置
func (s *MonitorService) BroadcastMonitorConfig(ctx context.Context) error {
// 获取所有启用的监控任务
var monitors []models.MonitorTask
if err := s.MonitorRepo.GetDB(ctx).
Where("enabled = ?", true).
Find(&monitors).Error; err != nil {
return err
}
// 如果没有启用的监控任务,直接返回(不需要发送任何配置)
if len(monitors) == 0 {
s.logger.Debug("没有启用的监控任务,跳过配置推送")
return nil
}
// 获取所有在线探针
agents, err := s.agentRepo.FindOnlineAgents(ctx)
if err != nil {
s.logger.Error("获取在线探针失败", zap.Error(err))
return err
}
// 按探针分组构建监控配置
agentMonitors := make(map[string][]models.MonitorTask)
for _, monitor := range monitors {
// 使用统一的方法计算目标探针
targetAgents := s.resolveTargetAgents(monitor, agents)
for _, agent := range targetAgents {
agentMonitors[agent.ID] = append(agentMonitors[agent.ID], monitor)
}
}
// 向每个有监控任务的探针发送对应的监控配置
for agentID, tasks := range agentMonitors {
items := make([]protocol.MonitorItem, 0, len(tasks))
for _, task := range tasks {
item := protocol.MonitorItem{
ID: task.ID,
Type: task.Type,
Target: task.Target,
}
if task.Type == "http" || task.Type == "https" {
var httpConfig protocol.HTTPMonitorConfig
if err := task.HTTPConfig.Scan(&httpConfig); err == nil {
item.HTTPConfig = &httpConfig
}
} else if task.Type == "tcp" {
var tcpConfig protocol.TCPMonitorConfig
if err := task.TCPConfig.Scan(&tcpConfig); err == nil {
item.TCPConfig = &tcpConfig
}
} else if task.Type == "icmp" || task.Type == "ping" {
var icmpConfig protocol.ICMPMonitorConfig
if err := task.ICMPConfig.Scan(&icmpConfig); err == nil {
item.ICMPConfig = &icmpConfig
}
}
items = append(items, item)
}
// 构建监控配置 payload
// Interval 字段不再使用(探针收到后立即检测一次),但保留字段兼容性
payload := protocol.MonitorConfigPayload{
Interval: 0,
Items: items,
}
// 发送监控配置到指定探针
if err := s.sendMonitorConfigToAgent(agentID, payload); err != nil {
s.logger.Error("发送监控配置失败",
zap.String("agentID", agentID),
zap.Error(err))
} else {
s.logger.Debug("发送监控配置成功",
zap.String("agentID", agentID),
zap.Int("taskCount", len(items)))
}
}
return nil
}
// sendMonitorConfigToAgent 向指定探针发送监控配置(内部方法)
func (s *MonitorService) sendMonitorConfigToAgent(agentID string, payload protocol.MonitorConfigPayload) error {
payloadData, err := json.Marshal(payload)
@@ -688,24 +601,38 @@ func (s *MonitorService) GetMonitorStatsByID(ctx context.Context, monitorID stri
return nil, err
}
// 获取探针列表
agents, err := s.agentRepo.FindAll(ctx)
if err != nil {
return nil, err
}
// 当前监控任务的关联的探针
targetAgents := s.resolveTargetAgents(monitor, agents)
var targetAgentsMap = make(map[string]string)
for _, agent := range targetAgents {
targetAgentsMap[agent.ID] = agent.Name
}
// 填充监控名称、探针名称和隐私设置
for i := range statsList {
statsList[i].MonitorName = monitor.Name
statsList[i].ShowTargetPublic = monitor.ShowTargetPublic
var filteredStatsList []models.MonitorStats
for _, stats := range statsList {
agentName, ok := targetAgentsMap[stats.AgentID]
if !ok {
continue
}
stats.MonitorName = monitor.Name
// 根据 ShowTargetPublic 字段决定是否隐藏 Target
if !monitor.ShowTargetPublic {
statsList[i].Target = "***"
stats.Target = "******"
}
// 查询探针名称
agent, err := s.agentRepo.FindById(ctx, statsList[i].AgentID)
if err == nil {
statsList[i].AgentName = agent.Name
}
stats.AgentName = agentName
filteredStatsList = append(filteredStatsList, stats)
}
return statsList, nil
return filteredStatsList, nil
}
// GetMonitorHistory 获取监控任务的历史响应时间数据
+1 -1
View File
@@ -38,7 +38,7 @@ func InitializeApp(logger *zap.Logger, db *gorm.DB, cfg *config.AppConfig) (*App
alertService := service.NewAlertService(logger, db, propertyService, notifier)
alertHandler := handler.NewAlertHandler(logger, alertService)
propertyHandler := handler.NewPropertyHandler(logger, propertyService, notifier)
monitorHandler := handler.NewMonitorHandler(logger, monitorService)
monitorHandler := handler.NewMonitorHandler(logger, monitorService, agentService)
tamperHandler := handler.NewTamperHandler(logger, tamperService)
appComponents := &AppComponents{
AccountHandler: accountHandler,
+2 -2
View File
@@ -259,7 +259,7 @@ const MonitorList = () => {
{hasAgents && (
<Space wrap size={4}>
<span className="text-xs text-gray-500">探针:</span>
{record.agentIds.map((id) => (
{record.agentNames?.map((id) => (
<Tag key={id} color="blue">{id}</Tag>
))}
</Space>
@@ -267,7 +267,7 @@ const MonitorList = () => {
{hasTags && (
<Space wrap size={4}>
<span className="text-xs text-gray-500">标签:</span>
{record.tags.map((tag) => (
{record.tags?.map((tag) => (
<Tag key={tag} color="green">{tag}</Tag>
))}
</Space>
+1 -1
View File
@@ -392,7 +392,7 @@ const MonitorDetail = () => {
<h1 className="text-3xl font-semibold">{monitorTitle}</h1>
</div>
<p className="mt-2 text-sm text-white/80">
{firstStat.showTargetPublic ? firstStat.target : '***'}
{firstStat.target}
</p>
<p className="text-xs text-white/60">公共视图 · 实时监控概览</p>
</div>
+1 -1
View File
@@ -253,6 +253,7 @@ export interface MonitorTask {
tcpConfig?: MonitorTcpConfig | null;
icmpConfig?: MonitorIcmpConfig | null;
agentIds?: string[];
agentNames?: string[];
tags?: string[]; // 标签列表,拥有这些标签的探针都会执行此监控
createdAt: number;
updatedAt: number;
@@ -312,7 +313,6 @@ export interface MonitorStats {
name: string; // 监控项名称
type: string;
target: string;
showTargetPublic: boolean; // 在公开页面是否显示目标地址
currentResponse: number; // 当前响应时间(ms)
avgResponse24h: number; // 24小时平均响应时间(ms)
uptime24h: number; // 24小时在线率(百分比)