package service import ( "errors" "github.com/prometheus/alertmanager/notify/webhook" "github.com/spf13/cast" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/constant" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" "go.uber.org/zap" "time" "xorm.io/xorm" ) type AlertWebhookSvc struct { User entity.SystemUserInfo } // AlertWebhook Alertmanager 回调接口 func (a *AlertWebhookSvc) AlertWebhook(session *xorm.Session, req webhook.Message) (err error) { now := jsontime.Now() alertSvc := AlertSvc{User: a.User} alertRulesSvc := AlertRulesSvc{User: a.User} for _, alert := range req.Alerts { var ( alertRulesId string riskLevelStr string riskLevel int currentValueStr string currentValue float64 ok bool alertItem response.AlertItem alertRulesItem response.AlertRulesItem alertStatus int alertCondition entity.AlertCondition ) if alertRulesId, ok = alert.Labels["alert_rules_id"]; !ok { err = errors.New("alert_rules_id not found in the map") conf.Logger.Error("err", zap.Error(err)) } if riskLevelStr, ok = alert.Labels["risk_level"]; !ok { err = errors.New("risk_level not found in the map") conf.Logger.Error("err", zap.Error(err)) } riskLevel = cast.ToInt(riskLevelStr) if currentValueStr, ok = alert.Annotations["value"]; !ok { err = errors.New("value not found in the map") conf.Logger.Error("err", zap.Error(err)) return } currentValue = cast.ToFloat64(currentValueStr) alertRulesItem, err = alertRulesSvc.GetDataById(request.DetailAlertRules{Id: alertRulesId}) if err != nil { return } if alertRulesItem.Id == "" { conf.Logger.Error("err", zap.Error(errors.New("告警规则查询为空"))) return } alertItem, err = alertSvc.GetDataByAlertRulesIdAndRiskLevel(alertRulesId, riskLevel, 2) if err != nil { return } var isNewAlert bool if alertItem.Id == 0 { // 新数据 isNewAlert = true } switch isNewAlert { case true: // 新增数据到OpenSearch var max int max, err = alertSvc.GetIndexMaxID(conf.Options.OpenSearchIndex) if err != nil { // 获取id最大值 max = alertSvc.CatCount(conf.Options.OpenSearchIndex) } if max == 0 { err = errors.New("failed to get doc count for index") conf.Logger.Error("err", zap.Error(err)) return } id := max + 1 for _, v := range alertRulesItem.AlertCondition { if v.RiskLevel == riskLevel { alertCondition = v break } } createAlert := request.CreateAlert{Alert: entity.Alert{ Id: id, AlertPoint: alertRulesItem.ClassParentName + "/" + alertRulesItem.MetricName, AlertRulesId: alertRulesItem.Id, AlertRulesName: alertRulesItem.MetricName, RiskLevel: riskLevel, AlertTime: jsontime.Time(alert.StartsAt.Add(time.Hour * 8)), ClassId: alertRulesItem.ClassId, ClassParentName: alertRulesItem.ClassParentName, ClassName: alertRulesItem.ClassName, MetricConfigId: alertRulesItem.MetricConfigId, MetricConfigName: alertRulesItem.MetricConfigName, AlertRuleType: alertRulesItem.AlertRuleType, AlertRuleTypeName: alertRulesItem.AlertRuleTypeName, CurrentValue: currentValue, AlertCondition: alertCondition, NotificationCount: len(alertRulesItem.NotifyRecipients), PushCount: 1, LastPushTime: now, Status: constant.AlertNotRecovered, CreatedBy: a.User.SystemAccount, CreatedAt: now, UpdatedBy: a.User.SystemAccount, UpdatedAt: now, }} err = alertSvc.DocCreate(createAlert) if err != nil { return } // 新数据发送短信 var ( phones []string pushRecords []entity.PushRecord ) for k, v := range alertRulesItem.NotifyRecipients { phones = append(phones, v.Phone) pushRecords = append(pushRecords, entity.PushRecord{ Id: k + 1, AlertId: createAlert.Id, AlertRulesId: createAlert.AlertRulesId, RiskLevel: createAlert.RiskLevel, NotifyMethod: alertRulesItem.NotifyMethod, SystemAccount: v.SystemAccount, PushTime: now, PushType: 1, Status: 1, UserName: v.UserName, Phone: v.Phone, CreatedBy: a.User.SystemAccount, CreatedAt: now, UpdatedBy: a.User.SystemAccount, UpdatedAt: now, }) } for _, method := range alertRulesItem.NotifyMethod { switch method { // dingtalk sms case "sms": // 发送短信 smsErr := alertSvc.Sms( phones, createAlert.ClassParentName, createAlert.ClassName, createAlert.AlertPoint, createAlert.MetricConfigName, cast.ToString(createAlert.CurrentValue), constant.RiskLeveText(createAlert.RiskLevel)) if smsErr != nil { // 短信推送失败 for i := 0; i < len(pushRecords); i++ { pushRecords[i].Status = 2 } } case "dingtalk": smsErr := alertSvc.DingTalkMsg( phones, createAlert.ClassParentName, createAlert.ClassName, createAlert.AlertPoint, createAlert.MetricConfigName, cast.ToString(createAlert.CurrentValue), constant.RiskLeveText(createAlert.RiskLevel)) if smsErr != nil { // 短信推送失败 for i := 0; i < len(pushRecords); i++ { pushRecords[i].Status = 2 } } } } err = alertSvc.Update(request.UpdateAlert{Id: createAlert.Id, PushRecords: pushRecords}) default: // 旧数据,更新或解决 switch alert.Status { case "firing": alertStatus = constant.AlertNotRecovered case "resolved": alertStatus = constant.AlertRecovered } err = alertSvc.Update(request.UpdateAlert{ Id: alertItem.Id, CurrentValue: currentValue, RiskLevel: riskLevel, Status: alertStatus, }) } } return }