package ingest import ( "bytes" "encoding/json" "fmt" "net/http" "time" "git.apinb.com/ops/logs/internal/config" ) // AlertReceiveBody 与 alert ReceiveRequest 对齐(含必填 raw_data) type AlertReceiveBody struct { AlertName string `json:"alert_name"` Summary string `json:"summary"` Description string `json:"description"` SeverityCode string `json:"severity_code"` Value string `json:"value"` Threshold string `json:"threshold"` Labels map[string]string `json:"labels"` Agent string `json:"agent"` PolicyID uint `json:"policy_id"` RawData json.RawMessage `json:"raw_data"` } func forwardAlert(body AlertReceiveBody) error { cfg := config.Spec.AlertForward if cfg == nil || !cfg.Enabled || cfg.BaseURL == "" { return nil } if len(body.RawData) == 0 { return fmt.Errorf("raw_data 不能为空") } if body.AlertName == "" { body.AlertName = "日志告警" } if body.PolicyID == 0 && cfg.DefaultPolicyID > 0 { body.PolicyID = cfg.DefaultPolicyID } raw, err := json.Marshal(body) if err != nil { return err } url := cfg.BaseURL + "/Alert/v1/alerts/receive" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(raw)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") if cfg.InternalKey != "" { req.Header.Set("X-Internal-Key", cfg.InternalKey) } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("alert returned HTTP %d", resp.StatusCode) } return nil }