diff --git a/src/bean/entity/alert.go b/src/bean/entity/alert.go index 5f6617dfc800526ca8183a0f8e7e5e877f7deed1..ddad854623648c15c391cdf4db3befac5c4edb9d 100644 --- a/src/bean/entity/alert.go +++ b/src/bean/entity/alert.go @@ -6,34 +6,36 @@ import ( // Alert 预警表 type Alert struct { - Id int `json:"id"` // 预警列表ID,主键,自增长 - AlertPoint string `json:"alert_point"` // 预警点 - AlertRulesId string `json:"alert_rules_id"` // 告警规则id - RiskLevel int `json:"risk_level"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 - AlertTime jsontime.Time `json:"alert_time"` // 预警时间 - ClassId int `json:"class_id"` // 预警对象id(级联:预警分类/预警对象) - ClassParentName string `json:"class_parent_name"` // 预警分类名称 TODO 该字段做关联存储或查询 - ClassName string `json:"class_name"` // 预警对象名称 TODO 该字段做关联存储或查询 - MetricConfigId string `json:"metric_config_id"` // 预警指标id // 预警指标 - MetricConfigName string `json:"metric_config_name"` // 预警指标名称 - AlertRuleType string `json:"alert_rule_type"` // 预警规则类型id TODO 该字段做关联存储或查询 - AlertRuleTypeName string `json:"alert_rule_type_name"` // 预警规则类型名称 TODO 该字段做关联存储或查询 - CurrentValue float64 `json:"current_value"` // 当前报警值 - AlertCondition string `json:"alert_condition" xorm:"'alert_condition'"` // 预警规则(预警阈值) 字典值 - NotificationCount int `json:"notification_count"` // 通知人数 - PushCount int `json:"push_count"` // 推送次数 - LastPushTime jsontime.Time `json:"last_push_time"` // 最近推送时间 - Status int `json:"status"` // 状态,1:已恢复 2:未恢复 3:已关闭 - DisposedList []DisposedList `json:"disposed_list"` // 处置列表 - IsDisposed int `json:"is_disposed"` // 是否处置(工单管理),1:已处置,2:未处置 通过DisposedList逻辑处理回显 - CloseRemark string `json:"close_remark"` // 关闭备注(预警关闭提醒) - CloseUser string `json:"close_user"` // 关闭用户,预警关闭提醒 - CloseTime jsontime.Time `json:"close_time"` // 关闭关闭时间,预警关闭提醒 - DeferPush int `json:"defer_push" xorm:"defer_push"` // 延迟三天推送: 0:否 1:是 三天内将不再自动推送该告警信息给处置人员,可手动推送,但告警数据依然会出现 - CreatedBy string `json:"created_by" xorm:"'created_by'"` // 创建人 - CreatedAt jsontime.Time `json:"created_at" xorm:"'created_at'"` // 创建时间 - UpdatedBy string `json:"updated_by" xorm:"'updated_by'"` // 更新人 - UpdatedAt jsontime.Time `json:"updated_at" xorm:"'updated_at'"` // 更新时间 + Id int `json:"id"` // 预警列表ID,主键,自增长 + AlertPoint string `json:"alert_point"` // 预警点 + AlertRulesId string `json:"alert_rules_id"` // 告警规则id + RiskLevel int `json:"risk_level"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 + AlertTime jsontime.Time `json:"alert_time"` // 预警时间 + ClassId int `json:"class_id"` // 预警对象id(级联:预警分类/预警对象) + ClassParentName string `json:"class_parent_name"` // 预警分类名称 TODO 该字段做关联存储或查询 + ClassName string `json:"class_name"` // 预警对象名称 TODO 该字段做关联存储或查询 + MetricConfigId string `json:"metric_config_id"` // 预警指标id // 预警指标 + MetricConfigName string `json:"metric_config_name"` // 预警指标名称 + AlertRuleType string `json:"alert_rule_type"` // 预警规则类型id TODO 该字段做关联存储或查询 + AlertRuleTypeName string `json:"alert_rule_type_name"` // 预警规则类型名称 TODO 该字段做关联存储或查询 + CurrentValue float64 `json:"current_value"` // 当前报警值 + AlertCondition AlertCondition `json:"alert_condition" xorm:"alert_condition"` + NotificationCount int `json:"notification_count"` // 通知人数 + PushCount int `json:"push_count"` // 推送次数 + LastPushTime jsontime.Time `json:"last_push_time"` // 最近推送时间 + Status int `json:"status"` // 状态,1:已恢复 2:未恢复 3:已关闭 + PushRecords []PushRecord `json:"push_records"` + DisposedList []DisposedList `json:"disposed_list"` // 处置列表 + IsDisposed int `json:"is_disposed"` // 是否处置(工单管理),1:已处置,2:未处置 通过DisposedList逻辑处理回显 + CloseRemark string `json:"close_remark"` // 关闭备注(预警关闭提醒) + CloseUser string `json:"close_user"` // 关闭用户,预警关闭提醒 + CloseTime jsontime.Time `json:"close_time"` // 关闭关闭时间,预警关闭提醒 + DeferPush int `json:"defer_push" xorm:"defer_push"` // 延迟三天推送: 0:否 1:是 三天内将不再自动推送该告警信息给处置人员,可手动推送,但告警数据依然会出现 + + CreatedBy string `json:"created_by" xorm:"'created_by'"` // 创建人 + CreatedAt jsontime.Time `json:"created_at" xorm:"'created_at'"` // 创建时间 + UpdatedBy string `json:"updated_by" xorm:"'updated_by'"` // 更新人 + UpdatedAt jsontime.Time `json:"updated_at" xorm:"'updated_at'"` // 更新时间 } type DisposedList struct { @@ -43,6 +45,12 @@ type DisposedList struct { DisposalTime jsontime.Time `json:"disposal_time"` // 处置时间(工单管理,结果反馈) } +type OpenSearchIds struct { + Ids struct { + Values []string `json:"values"` + } `json:"ids"` +} + func (a *Alert) TableName() string { return "alert" } diff --git a/src/bean/entity/push_record.go b/src/bean/entity/push_record.go index fb4351cd7a79523a0fe582ab3e09ef3fb10095ac..8aa3fb09c50b850abf9bd0b399c593cf2ff5d29c 100644 --- a/src/bean/entity/push_record.go +++ b/src/bean/entity/push_record.go @@ -7,11 +7,13 @@ type PushRecord struct { AlertId int `json:"alert_id" xorm:"alert_id"` // 告警id AlertRulesId string `json:"alert_rules_id" xorm:"'alert_rules_id'"` // 告警规则id RiskLevel int `json:"risk_level" xorm:"'risk_level'"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 - NotifyMethod string `json:"notify_method" xorm:"'notify_method'"` // 预警通知方式 dingtalk sms + NotifyMethod []string `json:"notify_method" xorm:"notify_method"` // 预警通知方式 dingtalk sms SystemAccount string `json:"system_account" xorm:"system_account"` // 预警推送用户 PushTime jsontime.Time `json:"push_time" xorm:"'push_time'"` // 推送时间 PushType int `json:"push_type" xorm:"'push_type'"` // 推送类型,1:自动推送,2:手动推送 Status int `json:"status" xorm:"'status'"` // 推送状态,1:成功,2:失败 + UserName string `json:"user_name" xorm:"user_name"` // 推送用户名称 + Phone string `json:"phone" xorm:"phone"` // 推送手机号 CreatedBy string `json:"created_by" xorm:"'created_by'"` // 创建人 CreatedAt jsontime.Time `json:"created_at" xorm:"'created_at'"` // 创建时间 UpdatedBy string `json:"updated_by" xorm:"'updated_by'"` // 更新人 diff --git a/src/bean/vo/request/alert.go b/src/bean/vo/request/alert.go index 2e045b031c188049665e64074f45b970f294bfff..009ac6e555f1a4284070f6bc3281254be9f89db6 100644 --- a/src/bean/vo/request/alert.go +++ b/src/bean/vo/request/alert.go @@ -11,11 +11,12 @@ type DetailAlert struct { type UpdateAlert struct { Id int `json:"id" form:"id" binding:"required"` //Ids []int `json:"ids" form:"ids" binding:"required_without=Id"` // 预警ids - CloseRemark string `json:"close_remark" form:"close_remark"` // 关闭备注 - DeferPush int `json:"defer_push" form:"defer_push" binding:"omitempty,oneof=0 1"` // 延迟三天推送: 0:否 1:是 三天内将不再自动推送该告警信息给处置人员,可手动推送,但告警数据依然会出现 - RiskLevel int `json:"risk_level" form:"risk_level" binding:"omitempty,oneof=1 2 3 4"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 - Status int `json:"status" form:"status" binding:"omitempty,oneof=1 2 3"` // 状态,1:已恢复 2:未恢复 3:已关闭 - DisposalContent string `json:"disposal_content" form:"disposal_content"` // 处置内容(工单管理,结果反馈) + CloseRemark string `json:"close_remark" form:"close_remark"` // 关闭备注 + DeferPush int `json:"defer_push" form:"defer_push" binding:"omitempty,oneof=0 1"` // 延迟三天推送: 0:否 1:是 三天内将不再自动推送该告警信息给处置人员,可手动推送,但告警数据依然会出现 + RiskLevel int `json:"risk_level" form:"risk_level" binding:"omitempty,oneof=1 2 3 4"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 + Status int `json:"status" form:"status" binding:"omitempty,oneof=1 2 3"` // 状态,1:已恢复 2:未恢复 3:已关闭 + DisposalContent string `json:"disposal_content" form:"disposal_content"` // 处置内容(工单管理,结果反馈) + PushRecords []entity.PushRecord `json:"push_records" form:"push_records"` } type BatchPushAlert struct { @@ -34,6 +35,7 @@ type BatchCloseAlert struct { type ListAlert struct { Id int `json:"id" form:"id"` + Ids []int `json:"ids" form:"ids" binding:"required_without=Id"` // 预警ids RiskLevel int `json:"risk_level" form:"risk_level" binding:"omitempty,oneof=1 2 3 4"` // 风险等级,1:低风险,2:一般风险,3:较大风险,4:重大风险 Status int `json:"status" form:"status" binding:"omitempty,oneof=1 2 3"` // 状态,1:已恢复 2:未恢复 3:已关闭 Keyword string `json:"keyword" form:"keyword"` // 预警点/分类/指标 diff --git a/src/bean/vo/response/alert.go b/src/bean/vo/response/alert.go index 994ca2ad547455b7d370463fa0ae6e2fa7365ed3..cdc17ba8d6010d3b95af4454dd979841c540632d 100644 --- a/src/bean/vo/response/alert.go +++ b/src/bean/vo/response/alert.go @@ -5,9 +5,7 @@ import ( ) type AlertItem struct { - entity.Alert `xorm:"extends"` - AlertCondition entity.AlertCondition `json:"alert_condition" xorm:"alert_condition"` - PushRecords []PushRecordItem `json:"push_records"` + entity.Alert `xorm:"extends"` } type AlertList struct { diff --git a/src/bean/vo/response/push_record.go b/src/bean/vo/response/push_record.go index c3a85e2dbc5aebd7db835a8705dd7734f3b04346..a615bbd8cdd1fb3c4c684957826ade5f332b0266 100644 --- a/src/bean/vo/response/push_record.go +++ b/src/bean/vo/response/push_record.go @@ -4,7 +4,6 @@ import "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" type PushRecordItem struct { entity.PushRecord `xorm:"extends"` - NotifyMethod []string `json:"notify_method" xorm:"notify_method"` // 预警通知方式 dingtalk sms } type PushRecordList struct { diff --git a/src/controller/alert.go b/src/controller/alert.go index 7aa7924eaec8b47a436bedf06c27456b09ccef4b..bbe038b079f4840a899eafa8dd96ec59c4cad22f 100644 --- a/src/controller/alert.go +++ b/src/controller/alert.go @@ -3,7 +3,6 @@ package controller import ( "github.com/gin-gonic/gin" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" - "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/router/middleware/header" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/service" @@ -33,12 +32,7 @@ func BatchPushAlert(c *gin.Context) { } svc := service.AlertSvc{User: header.GetUser(c)} - db, err := client.GetDbClient() - if err != nil { - SendJsonResponse(c, resp.DbConnectError.WithError(err), nil) - return - } - err = svc.BatchPushAlert(db.NewSession(), req) + err := svc.BatchPushAlert(req) if err != nil { SendJsonResponse(c, resp.FAIL.WithError(err), nil) return diff --git a/src/service/alert.go b/src/service/alert.go index 0967bf34fa01786742622d0d6569be813a3fa82f..ab2ec2dfd3898b80b1a1414ac1816bc9a72710b8 100644 --- a/src/service/alert.go +++ b/src/service/alert.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/jinzhu/copier" json "github.com/json-iterator/go" "github.com/olivere/elastic/v7" "github.com/opensearch-project/opensearch-go/opensearchapi" @@ -16,14 +15,12 @@ import ( "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" - "gitlab.wodcloud.com/smart-operation/so-operation-api/src/util" "go.uber.org/zap" "io" "log" "net/http" "strings" "time" - "xorm.io/xorm" ) type AlertSvc struct { @@ -44,7 +41,13 @@ var ( "type": "integer" }, "alert_point": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "alert_rules_id": { "type": "keyword" @@ -54,29 +57,53 @@ var ( }, "alert_time": { "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", + "ignore_malformed": true }, "class_id": { "type": "integer" }, "class_parent_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "class_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "metric_config_id": { "type": "keyword" }, "metric_config_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "alert_rule_type": { "type": "keyword" }, "alert_rule_type_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "current_value": { "type": "integer" @@ -89,28 +116,81 @@ var ( }, "last_push_time": { "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", + "ignore_malformed": true }, "status": { "type": "integer" }, - "disposed_list": { + "push_records": { "type": "nested", "properties": { - "is_disposed": { + "id": { "type": "integer" }, - "disposal_content": { + "alert_id": { + "type": "integer" + }, + "alert_rules_id": { + "type": "keyword" + }, + "risk_level": { + "type": "integer" + }, + "notify_method": { + "type": "keyword" + }, + "system_account": { "type": "keyword" }, + "push_type": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "user_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "phone": { + "type": "keyword" + }, + "created_by": { + "type": "keyword" + }, + "updated_by": { + "type": "keyword" + } + } + }, + "disposed_list": { + "type": "nested", + "properties": { + "disposal_content": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_disposed": { + "type": "integer" + }, "disposal_user": { "type": "keyword" }, "disposal_time": { "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", + "ignore_malformed": true } } }, @@ -118,35 +198,35 @@ var ( "type": "integer" }, "close_remark": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "close_user": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "close_time": { - "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "defer_push": { "type": "integer" }, - "created_by": { - "type": "keyword" - }, - "created_at": { - "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" - }, - "updated_by": { - "type": "keyword" - }, - "updated_at": { - "type": "date", - "ignore_malformed": true, - "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" - }, "alert_condition": { "properties": { "thresholds_min": { @@ -159,6 +239,31 @@ var ( "type": "integer" } } + }, + "disposal_content": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "created_by": { + "type": "keyword" + }, + "created_at": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", + "ignore_malformed": true + }, + "updated_by": { + "type": "keyword" + }, + "updated_at": { + "type": "date", + "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", + "ignore_malformed": true } } } @@ -281,6 +386,22 @@ func (a *AlertSvc) IndexSearch(req request.ListAlert) (resp response.AlertList, b, _ := json.Marshal(querySource) log.Printf("es statements: %s\n", string(b)) + if len(req.Ids) > 0 { + var idsStr []string + for _, id := range req.Ids { + idsStr = append(idsStr, cast.ToString(id)) + } + ids := entity.OpenSearchIds{ + Ids: struct { + Values []string `json:"values"` + }{idsStr}, + } + b, err = json.Marshal(&ids) + if err != nil { + return + } + } + content := strings.NewReader(fmt.Sprintf(`{ "query": %s, "from": %d, @@ -289,6 +410,7 @@ func (a *AlertSvc) IndexSearch(req request.ListAlert) (resp response.AlertList, res := opensearchapi.SearchRequest{ Index: []string{OpenSearchIndex}, Body: content, + Sort: []string{"id"}, } do, err := res.Do(context.Background(), cli) if err != nil { @@ -357,6 +479,10 @@ func (a *AlertSvc) IndexUpdate(req request.UpdateAlert) (err error) { doc["disposed_list"] = disposedList } + if len(req.PushRecords) > 0 { + doc["push_records"] = req.PushRecords + } + if len(doc) == 0 { return errors.New("no updated fields") } @@ -405,17 +531,47 @@ func (a *AlertSvc) Update(req request.UpdateAlert) error { return err } -func (a *AlertSvc) BatchPushAlert(session *xorm.Session, req request.BatchPushAlert) error { +func (a *AlertSvc) BatchPushAlert(req request.BatchPushAlert) (err error) { now := jsontime.Now() - data := entity.PushRecord{ - CreatedBy: a.User.SystemAccount, - CreatedAt: now, - UpdatedBy: a.User.SystemAccount, - UpdatedAt: now, - } - _ = copier.Copy(&data, &req) - data.NotifyMethod = util.ConvertToString(req.NotifyMethod) - data.SystemAccount = util.ConvertToString(req.NotifyRecipients) // 循环查询 + resp, err := a.IndexSearch(request.ListAlert{Ids: req.Ids}) + if err != nil { + return + } + + for _, alert := range resp.List { + pushRecords := alert.PushRecords + pushCount := len(alert.PushRecords) + for _, v := range req.NotifyRecipients { + pushCount++ + data := entity.PushRecord{ + Id: pushCount, + AlertId: alert.Id, + AlertRulesId: alert.AlertRulesId, + RiskLevel: alert.RiskLevel, + NotifyMethod: req.NotifyMethod, + SystemAccount: v.SystemAccount, + PushTime: now, + PushType: 2, + Status: 0, // TODO 需要调用之后更新 + UserName: v.UserName, + Phone: v.Phone, + CreatedBy: a.User.SystemAccount, + CreatedAt: now, + UpdatedBy: a.User.SystemAccount, + UpdatedAt: now, + } + pushRecords = append(pushRecords, data) + } + + err = a.IndexUpdate(request.UpdateAlert{ + Id: alert.Id, + PushRecords: pushRecords, + }) + if err != nil { + return + } + } + // TODO 批量推送用户告警 conf.Logger.Info("batch push", zap.Any("payload", req)) time.Sleep(time.Second) diff --git a/src/service/push_record.go b/src/service/push_record.go index c832f73c70d9e3cf74a3ea3b63725c55906720de..a89b5ac616b04d88ed9a1bba0ee0f896606f0ae9 100644 --- a/src/service/push_record.go +++ b/src/service/push_record.go @@ -49,8 +49,10 @@ func (m *PushRecordSvc) GetDataById(req request.DetailPushRecord) (resp response data := response.PushRecordItem{ PushRecord: entity.PushRecord{ Id: 1, + AlertId: 1, AlertRulesId: "83343ef6-4a99-47bd-abb4-bcff52feb2ec", RiskLevel: 1, + NotifyMethod: []string{"dingtalk", "sms"}, SystemAccount: "xiaowang", PushTime: now, PushType: 1, @@ -60,7 +62,6 @@ func (m *PushRecordSvc) GetDataById(req request.DetailPushRecord) (resp response UpdatedBy: "admin", UpdatedAt: now, }, - NotifyMethod: []string{"dingtalk", "sms"}, } resp = data return @@ -81,8 +82,8 @@ func (m *PushRecordSvc) List(req request.ListPushRecord) (resp response.PushReco CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, + NotifyMethod: []string{"dingtalk", "sms"}, }, - NotifyMethod: []string{"dingtalk", "sms"}, } data2 := response.PushRecordItem{ PushRecord: entity.PushRecord{ @@ -97,8 +98,8 @@ func (m *PushRecordSvc) List(req request.ListPushRecord) (resp response.PushReco CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, + NotifyMethod: []string{"dingtalk", "sms"}, }, - NotifyMethod: []string{"dingtalk", "sms"}, } resp.List = append(resp.List, data1, data2) resp.TotalCount = int64(len(resp.List))