From e0ed7e80df269e6b14f2c3ed0320ea20bfd0128f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Fri, 12 Sep 2025 15:27:12 +0800 Subject: [PATCH] fix(monitor): history alert report (#23279) --- cmd/climc/shell/monitor/alertrecord.go | 1 + pkg/apis/monitor/alertrecord.go | 37 ++++--- pkg/cloudmon/misc/alerts.go | 67 ++++--------- pkg/mcclient/options/monitor/alertrecord.go | 12 +++ pkg/monitor/models/alertrecord.go | 101 ++++++++++++-------- 5 files changed, 116 insertions(+), 102 deletions(-) diff --git a/cmd/climc/shell/monitor/alertrecord.go b/cmd/climc/shell/monitor/alertrecord.go index 496ef13958..9a196d4e28 100644 --- a/cmd/climc/shell/monitor/alertrecord.go +++ b/cmd/climc/shell/monitor/alertrecord.go @@ -24,4 +24,5 @@ func init() { cmd.List(new(options.AlertRecordListOptions)) cmd.Show(new(options.AlertRecordShowOptions)) cmd.GetProperty(new(options.AlertRecordTotalOptions)) + cmd.GetProperty(new(options.AlertRecordHistoryAlertOptions)) } diff --git a/pkg/apis/monitor/alertrecord.go b/pkg/apis/monitor/alertrecord.go index b37b24c3c3..87e36472f8 100644 --- a/pkg/apis/monitor/alertrecord.go +++ b/pkg/apis/monitor/alertrecord.go @@ -53,20 +53,6 @@ type AlertRecordDetails struct { TriggerTime time.Time } -func (self AlertRecordDetails) GetMetricTags() map[string]string { - ret := map[string]string{ - "id": self.Id, - "alert_id": self.AlertId, - "alert_name": self.AlertName, - "domain_id": self.DomainId, - "project_domain": self.ProjectDomain, - "res_type": self.ResType, - "tenant": self.Tenant, - "tenant_id": self.TenantId, - } - return ret -} - type AlertRecordCreateInput struct { apis.StandaloneResourceCreateInput @@ -99,3 +85,26 @@ type AlertRecordRule struct { SilentPeriod string `json:"silent_period"` Reducer string `json:"reducer"` } + +type AlertRecordHistoryAlertData struct { + ProjectId string `json:"project_id"` + Project string `json:"project"` + DomainId string `json:"domain_id"` + Domain string `json:"domain"` + ResType string `json:"res_type"` + ResNum int64 `json:"res_num"` +} + +func (self AlertRecordHistoryAlertData) GetMetricTags() map[string]string { + return map[string]string{ + "project_id": self.ProjectId, + "domain_id": self.DomainId, + "domain": self.Domain, + "project": self.Project, + "res_type": self.ResType, + } +} + +type AlertRecordHistoryAlert struct { + Data []AlertRecordHistoryAlertData `json:"data"` +} diff --git a/pkg/cloudmon/misc/alerts.go b/pkg/cloudmon/misc/alerts.go index 824d712854..6a5f687655 100644 --- a/pkg/cloudmon/misc/alerts.go +++ b/pkg/cloudmon/misc/alerts.go @@ -19,13 +19,12 @@ import ( "fmt" "time" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/monitor" "yunion.io/x/onecloud/pkg/cloudcommon/tsdb" - "yunion.io/x/onecloud/pkg/cloutpost/options" + "yunion.io/x/onecloud/pkg/cloudmon/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules/monitor" @@ -40,67 +39,35 @@ const ( func AlertHistoryReport(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) { err := func() error { s := auth.GetAdminSession(ctx, options.Options.Region) - params := map[string]interface{}{ - "field": "res_type", - "scope": "system", - "filter.0": fmt.Sprintf("created_at.ge('%s')", time.Now().Add(time.Hour*-24)), - } - ret, err := monitor.AlertRecordManager.Get(s, "distinct-field", jsonutils.Marshal(params)) + resp, err := monitor.AlertRecordManager.Get(s, "history-alert", nil) if err != nil { - return errors.Wrapf(err, "distinct-filed") + return errors.Wrapf(err, "history-alert") + } + alerts := api.AlertRecordHistoryAlert{} + err = resp.Unmarshal(&alerts) + if err != nil { + return errors.Wrapf(err, "Unmarshal AlertRecordHistoryAlert") } - resTypes := []string{} - ret.Unmarshal(&resTypes, "res_type") metrics := []influxdb.SMetricData{} - for _, resType := range resTypes { - records := []api.AlertRecordDetails{} - for { - query := map[string]interface{}{ - "limit": 40, - "offset": len(records), - "@state": "alerting", - "scope": "system", - "filter.0": fmt.Sprintf(`res_type.equals('%s')`, resType), - "filter.1": fmt.Sprintf("created_at.ge('%s')", time.Now().Add(time.Hour*-24)), - } - ret, err := monitor.AlertRecordManager.List(s, jsonutils.Marshal(query)) - if err != nil { - log.Errorf("AlertRecordManager.List error: %v", err) - break - } - part := []api.AlertRecordDetails{} - err = jsonutils.Update(&part, ret.Data) - if err != nil { - break - } - records = append(records, part...) - if len(records) >= ret.Total { - break - } - } + for _, alert := range alerts.Data { metric := influxdb.SMetricData{} metric.Name = ALERT_RECORD_HISTORY_MEASUREMENT - cnt := 0 - for i, record := range records { - cnt += int(record.ResNum) - if i == 0 { - for k, v := range record.GetMetricTags() { - metric.Tags = append(metric.Tags, influxdb.SKeyValue{ - Key: k, - Value: v, - }) - } - } - } metric.Timestamp = time.Now() metric.Metrics = []influxdb.SKeyValue{ { Key: "res_num", - Value: fmt.Sprintf("%d", cnt), + Value: fmt.Sprintf("%d", alert.ResNum), }, } + for k, v := range alert.GetMetricTags() { + metric.Tags = append(metric.Tags, influxdb.SKeyValue{ + Key: k, + Value: v, + }) + } metrics = append(metrics, metric) } + urls, err := tsdb.GetDefaultServiceSourceURLs(s, options.Options.SessionEndpointType) if err != nil { return errors.Wrap(err, "GetServiceURLs") diff --git a/pkg/mcclient/options/monitor/alertrecord.go b/pkg/mcclient/options/monitor/alertrecord.go index be85d08302..b3e90dfd48 100644 --- a/pkg/mcclient/options/monitor/alertrecord.go +++ b/pkg/mcclient/options/monitor/alertrecord.go @@ -64,6 +64,18 @@ func (o *AlertRecordTotalOptions) Property() string { return "total-alert" } +type AlertRecordHistoryAlertOptions struct { + options.BaseListOptions +} + +func (o *AlertRecordHistoryAlertOptions) Params() (jsonutils.JSONObject, error) { + return options.ListStructToParams(o) +} + +func (o *AlertRecordHistoryAlertOptions) Property() string { + return "history-alert" +} + type AlertRecordShieldListOptions struct { options.BaseListOptions diff --git a/pkg/monitor/models/alertrecord.go b/pkg/monitor/models/alertrecord.go index a99815e266..9460b9f857 100644 --- a/pkg/monitor/models/alertrecord.go +++ b/pkg/monitor/models/alertrecord.go @@ -457,47 +457,72 @@ func (manager *SAlertRecordManager) GetPropertyTotalAlert(ctx context.Context, u return alertCountMap, nil } -/*func (manager *SAlertRecordManager) getNowAlertingRecord(ctx context.Context, userCred mcclient.TokenCredential, - input monitor.AlertRecordListInput) ([]SAlertRecord, error) { - //now := time.Now() - //startTime := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 1, now.Location()) - ownerId, err := manager.FetchOwnerId(ctx, jsonutils.Marshal(&input)) +// 获取过去一天的报警历史分布 +func (manager *SAlertRecordManager) GetPropertyHistoryAlert( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) (*monitor.AlertRecordHistoryAlert, error) { + q := manager.Query().GE("created_at", time.Now().Add(-time.Hour*24)).IsNotEmpty("eval_data").NotEquals("state", monitor.AlertStateOK) + alerts := []SAlertRecord{} + err := q.All(&alerts) if err != nil { - return nil, errors.Wrap(err, "FetchOwnerId error") - } - if ownerId == nil { - ownerId = userCred - } - query := manager.Query() - query = manager.FilterByOwner(ctx, query, manager, userCred, ownerId, rbacscope.String2Scope(input.Scope)) - //query = query.GE("created_at", startTime.UTC().Format(timeutils.MysqlTimeFormat)) - query = query.Equals("state", monitor.AlertStateAlerting) - query = query.IsNotNull("res_type").IsNotEmpty("res_type").Desc("created_at") - - if len(input.ResType) != 0 { - query = query.Equals("res_type", input.ResType) - } - - alertsQuery := CommonAlertManager.Query("id").Equals("state", monitor.AlertStateAlerting).IsTrue("enabled"). - IsNull("used_by") - alertsQuery = CommonAlertManager.FilterByOwner(ctx, alertsQuery, CommonAlertManager, userCred, userCred, rbacscope.String2Scope(input.Scope)) - alerts := make([]SCommonAlert, 0) - records := make([]SAlertRecord, 0) - err = db.FetchModelObjects(CommonAlertManager, alertsQuery, &alerts) - if err != nil { - return nil, err + return nil, errors.Wrap(err, "q.All") } + ret := map[string]map[string]map[string]int64{} + domainIds, projectIds := []string{}, []string{} + domainMap := map[string]string{} + projectMap := map[string]string{} for _, alert := range alerts { - tmp := *query - recordModel, err := db.NewModelObject(manager) - if err != nil { - return nil, errors.Wrapf(err, "NewModelObject %s", manager.Keyword()) + if _, ok := ret[alert.DomainId]; !ok { + ret[alert.DomainId] = map[string]map[string]int64{} + domainIds = append(domainIds, alert.DomainId) } - if err := (&tmp).Equals("alert_id", alert.GetId()).First(recordModel); err == nil { - records = append(records, *(recordModel.(*SAlertRecord))) - } else { - log.Warningf("get records of alert_id %s error: %v", alert.GetId(), err) + if _, ok := ret[alert.DomainId][alert.ProjectId]; !ok { + ret[alert.DomainId][alert.ProjectId] = map[string]int64{} + projectIds = append(projectIds, alert.ProjectId) + } + if _, ok := ret[alert.DomainId][alert.ProjectId][alert.ResType]; !ok { + ret[alert.DomainId][alert.ProjectId][alert.ResType] = 0 + } + eval := make([]monitor.EvalMatch, 0) + err := alert.EvalData.Unmarshal(&eval) + if err != nil { + continue + } + ret[alert.DomainId][alert.ProjectId][alert.ResType] += int64(len(eval)) + } + domains := []db.STenant{} + err = db.TenantCacheManager.GetDomainQuery().In("id", domainIds).All(&domains) + if err != nil { + return nil, errors.Wrap(err, "GetDomainQuery.In.All") + } + for _, domain := range domains { + domainMap[domain.Id] = domain.Name + } + + projects := []db.STenant{} + err = db.TenantCacheManager.GetTenantQuery().In("id", projectIds).All(&projects) + if err != nil { + return nil, errors.Wrap(err, "GetTenantQuery.In.All") + } + for _, project := range projects { + projectMap[project.Id] = project.Name + } + result := &monitor.AlertRecordHistoryAlert{} + for domainId, projects := range ret { + for projectId, resTypes := range projects { + for resType, alert := range resTypes { + result.Data = append(result.Data, monitor.AlertRecordHistoryAlertData{ + ProjectId: projectId, + Project: projectMap[projectId], + DomainId: domainId, + Domain: domainMap[domainId], + ResType: resType, + ResNum: alert, + }) + } } } - return records, nil -}*/ + return result, nil +}