Files
pika/internal/service/public_ip_service.go
dushixiang 6c8d2f13d3 feat: 告警规则实体化与服务监控按标签选探针
- 告警规则:独立实体(alert_rules 表),按优先级命中第一条生效;支持三种主机目标(全部/按主机/按标签)、7 类阈值、事件通知开关、IP 打码、推送渠道选择;未命中规则的主机不产生告警;列表支持外置启停
- 服务监控:新增按标签选择探针,与指定探针取并集,均为空时全部探针执行
- 公网 IP 采集:范围支持全部探针/按探针/按标签,兼容历史 custom 取值
- 告警历史:新增规则归属列;评估链路(指标/证书/服务下线/探针离线/到期提醒/事件通知)全部按主机命中规则驱动
- 设置页:左侧菜单改为浅色卡片容器并优化对比度,通知渠道移至公网 IP 采集之后;主菜单宽度调整为 240px
2026-08-23 19:53:35 +08:00

134 lines
3.2 KiB
Go

package service
import (
"context"
"encoding/json"
"time"
"github.com/pika-monitor/pika/internal/models"
"github.com/pika-monitor/pika/internal/protocol"
"github.com/pika-monitor/pika/internal/repo"
"github.com/pika-monitor/pika/internal/websocket"
"go.uber.org/zap"
"gorm.io/gorm"
)
type PublicIPService struct {
logger *zap.Logger
propertyService *PropertyService
agentRepo *repo.AgentRepo
wsManager *websocket.Manager
}
func NewPublicIPService(logger *zap.Logger, db *gorm.DB, propertyService *PropertyService, wsManager *websocket.Manager) *PublicIPService {
return &PublicIPService{
logger: logger,
propertyService: propertyService,
agentRepo: repo.NewAgentRepo(db),
wsManager: wsManager,
}
}
// Run 启动公网 IP 采集调度
func (s *PublicIPService) Run(ctx context.Context) {
s.logger.Info("公网 IP 采集定时任务已启动")
for {
select {
case <-ctx.Done():
s.logger.Info("公网 IP 采集定时任务已停止")
return
default:
}
config, err := s.propertyService.GetPublicIPConfig(context.Background())
if err != nil {
s.logger.Error("获取公网 IP 采集配置失败", zap.Error(err))
if !s.sleepWithCancel(ctx, time.Minute) {
return
}
continue
}
if !config.Enabled || (!config.IPv4Enabled && !config.IPv6Enabled) {
if !s.sleepWithCancel(ctx, 30*time.Second) {
return
}
continue
}
interval := time.Duration(config.IntervalSeconds) * time.Second
if interval <= 0 {
interval = 5 * time.Minute
}
if interval < 30*time.Second {
interval = 30 * time.Second
}
s.sendConfigToOnlineAgents(config)
if !s.sleepWithCancel(ctx, interval) {
return
}
}
}
func (s *PublicIPService) sendConfigToOnlineAgents(config *models.PublicIPConfig) {
agentIDs := s.wsManager.GetAllClients()
if len(agentIDs) == 0 {
return
}
// 批量查询探针标签,用于按标签匹配采集范围
agentTagMap := make(map[string][]string, len(agentIDs))
if agents, err := s.agentRepo.FindByIdIn(context.Background(), agentIDs); err == nil {
for _, agent := range agents {
agentTagMap[agent.ID] = agent.Tags
}
}
for _, agentID := range agentIDs {
if agentID == "" {
continue
}
agentTags := agentTagMap[agentID]
ipv4Enabled := config.IsIPv4Target(agentID, agentTags)
ipv6Enabled := config.IsIPv6Target(agentID, agentTags)
if !ipv4Enabled && !ipv6Enabled {
continue
}
msgData, err := json.Marshal(protocol.OutboundMessage{
Type: protocol.MessageTypePublicIPConfig,
Data: protocol.PublicIPConfigData{
Enabled: config.Enabled,
IntervalSeconds: config.IntervalSeconds,
IPv4Enabled: ipv4Enabled,
IPv6Enabled: ipv6Enabled,
IPv4APIs: config.IPv4APIs,
IPv6APIs: config.IPv6APIs,
},
})
if err != nil {
s.logger.Error("构建公网 IP 配置消息失败", zap.Error(err))
return
}
if err := s.wsManager.SendToClient(agentID, msgData); err != nil {
s.logger.Debug("发送公网 IP 配置失败", zap.String("agentID", agentID), zap.Error(err))
}
}
}
func (s *PublicIPService) sleepWithCancel(ctx context.Context, d time.Duration) bool {
timer := time.NewTimer(d)
defer timer.Stop()
select {
case <-ctx.Done():
return false
case <-timer.C:
return true
}
}