fix(monitor): 3.7 nodata and alertOverview fix

1.nodata相关逻辑调整
2.监控总览视图穿透,报警数量不一致问题修复
This commit is contained in:
zhaoxiangchun
2021-02-04 20:52:53 +08:00
parent 352fc030e4
commit 4e0ce5b9e8
7 changed files with 300 additions and 27 deletions

View File

@@ -117,7 +117,9 @@ type CommonAlertDetails struct {
NotifierId string `json:"notifier_id"`
Channel []string `json:"channel"`
Recipients []string `json:"recipients"`
Status string `json:"status"`
// 静默期
SilentPeriod string `json:"silent_period"`
Status string `json:"status"`
// 报警类型
AlertType string `json:"alert_type"`
CommonAlertMetricDetails []*CommonAlertMetricDetails `json:"common_alert_metric_details"`

View File

@@ -3,6 +3,7 @@ package conditions
import (
"context"
"fmt"
"sort"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
@@ -20,9 +21,10 @@ import (
const (
NO_DATA = "nodata"
HOST_TAG_NAME = "name"
HOST_TAG_IP = "access_ip"
HOST_TAG_BRAND = "brand"
HOST_TAG_NAME = "name"
HOST_TAG_IP = "access_ip"
RESOURCE_TAG_IP = "ips"
HOST_TAG_BRAND = "brand"
)
func init() {
@@ -76,6 +78,7 @@ serLoop:
}
}
allHosts, err := c.getOnecloudResources(context)
allHosts = c.filterAllResources(context, allHosts)
if err != nil {
return nil, errors.Wrap(err, "NoDataQueryCondition getOnecloudHosts error")
}
@@ -102,6 +105,128 @@ serLoop:
}, nil
}
func (c *NoDataQueryCondition) filterAllResources(context *alerting.EvalContext,
resources []jsonutils.JSONObject) []jsonutils.JSONObject {
if len(c.Query.Model.Tags) == 0 {
return resources
}
filterIdMap := make(map[string]jsonutils.JSONObject)
filterQuery := c.getFilterQuery()
intKey := make([]int, 0)
if len(filterQuery) != 0 {
for key, _ := range filterQuery {
intKey = append(intKey, key)
}
sort.Ints(intKey)
minKey := intKey[0]
if minKey != 0 {
filterQuery[0] = minKey - 1
}
} else {
filterQuery[0] = len(c.Query.Model.Tags) - 1
}
for start, end := range filterQuery {
filterResources := c.getFilterResources(context, start, end, resources)
filterIdMap = c.fillFilterRes(filterResources, filterIdMap)
}
filterRes := make([]jsonutils.JSONObject, 0)
for _, obj := range filterIdMap {
filterRes = append(filterRes, obj)
}
return filterRes
}
func (c *NoDataQueryCondition) fillFilterRes(filterRes []jsonutils.JSONObject,
filterIdMap map[string]jsonutils.JSONObject) map[string]jsonutils.JSONObject {
for _, res := range filterRes {
id, _ := res.GetString("id")
if _, ok := filterIdMap[id]; !ok {
filterIdMap[id] = res
}
}
return filterIdMap
}
func (c *NoDataQueryCondition) getFilterQuery() map[int]int {
length := len(c.Query.Model.Tags)
tagIndexMap := make(map[int]int)
for i := 0; i < length; i++ {
if c.Query.Model.Tags[i].Condition == "OR" {
andIndex := c.getTheAndOfConditionor(i + 1)
if andIndex == i+1 {
tagIndexMap[i] = i
continue
}
if andIndex == length {
for j := i; j < length; j++ {
tagIndexMap[j] = j
}
break
}
tagIndexMap[i] = andIndex
i = andIndex
}
}
return tagIndexMap
}
func (c *NoDataQueryCondition) getTheAndOfConditionor(start int) int {
for i := start; i < len(c.Query.Model.Tags); i++ {
if c.Query.Model.Tags[i].Condition != "AND" {
return i
}
}
return len(c.Query.Model.Tags)
}
func (c *NoDataQueryCondition) getFilterResources(evalContext *alerting.EvalContext, start int, end int,
resources []jsonutils.JSONObject) []jsonutils.JSONObject {
relationMap := c.getTagKeyRelationMap(evalContext)
tmp := resources
for i := start; i <= end; i++ {
tag := c.Query.Model.Tags[i]
relationKey := relationMap[tag.Key]
filterObj := make([]jsonutils.JSONObject, 0)
for _, res := range tmp {
val, _ := res.GetString(relationKey)
if c.Query.Model.Tags[i].Operator == "=" {
if val == c.Query.Model.Tags[i].Value {
filterObj = append(filterObj, res)
}
}
if c.Query.Model.Tags[i].Operator == "!=" {
if val != c.Query.Model.Tags[i].Value {
filterObj = append(filterObj, res)
}
}
}
tmp = filterObj
if len(tmp) == 0 {
return tmp
}
}
return tmp
}
func (c *NoDataQueryCondition) getTagKeyRelationMap(evalContext *alerting.EvalContext) map[string]string {
relationMap := make(map[string]string)
switch evalContext.Rule.RuleDescription[0].ResType {
case monitor.METRIC_RES_TYPE_HOST:
relationMap = HostTags
case monitor.METRIC_RES_TYPE_GUEST:
relationMap = ServerTags
case monitor.METRIC_RES_TYPE_RDS:
relationMap = RdsTags
case monitor.METRIC_RES_TYPE_REDIS:
relationMap = RedisTags
case monitor.METRIC_RES_TYPE_OSS:
relationMap = OssTags
default:
relationMap = HostTags
}
return relationMap
}
func (c *NoDataQueryCondition) getOnecloudResources(evalContext *alerting.EvalContext) ([]jsonutils.JSONObject, error) {
var err error
allResources := make([]jsonutils.JSONObject, 0)
@@ -111,12 +236,12 @@ func (c *NoDataQueryCondition) getOnecloudResources(evalContext *alerting.EvalCo
query := jsonutils.NewDict()
query.Add(jsonutils.NewStringArray([]string{"running", "ready"}), "status")
query.Add(jsonutils.NewString("true"), "admin")
if len(c.Query.Model.Tags) != 0 {
query, err = c.convertTagsQuery(evalContext, query)
if err != nil {
return nil, errors.Wrap(err, "NoDataQueryCondition convertTagsQuery error")
}
}
//if len(c.Query.Model.Tags) != 0 {
// query, err = c.convertTagsQuery(evalContext, query)
// if err != nil {
// return nil, errors.Wrap(err, "NoDataQueryCondition convertTagsQuery error")
// }
//}
switch evalContext.Rule.RuleDescription[0].ResType {
case monitor.METRIC_RES_TYPE_HOST:
query.Set("host-type", jsonutils.NewString(hostconsts.TELEGRAF_TAG_KEY_HYPERVISOR))
@@ -171,6 +296,7 @@ func ListAllResources(manager modulebase.Manager, params *jsonutils.JSONDict) ([
}
params.Add(jsonutils.NewString("system"), "scope")
params.Add(jsonutils.NewInt(0), "limit")
params.Add(jsonutils.NewBool(true), "details")
var count int
session := auth.GetAdminSession(context.Background(), "", "")
objs := make([]jsonutils.JSONObject, 0)
@@ -223,6 +349,9 @@ func (c *NoDataQueryCondition) createEvalMatchTagFromHostJson(evalContext *alert
evalMatch.Tags = make(map[string]string, 0)
ip, _ := host.GetString(HOST_TAG_IP)
if ip == "" {
ip, _ = host.GetString(RESOURCE_TAG_IP)
}
name, _ := host.GetString(HOST_TAG_NAME)
brand, _ := host.GetString(HOST_TAG_BRAND)
evalMatch.Tags["ip"] = ip
@@ -250,3 +379,138 @@ func newNoDataQueryCondition(model *monitor.AlertCondition, index int) (*NoDataQ
condition.QueryCondition = queryCondition
return condition, nil
}
var (
ServerTags = map[string]string{
"host": "host",
"host_id": "host_id",
"vm_id": "id",
"vm_ip": "ips",
"vm_name": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"region_ext_id": "region_ext_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"scaling_group_id": "vm_scaling_group_id",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
HostTags = map[string]string{
"host_id": "id",
"host_ip": "ips",
"host": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"region_ext_id": "region_ext_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
RdsTags = map[string]string{
"host": "host",
"host_id": "host_id",
"rds_id": "id",
"rds_ip": "ips",
"rds_name": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"region_ext_id": "region_ext_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
RedisTags = map[string]string{
"host": "host",
"host_id": "host_id",
"redis_id": "id",
"redis_ip": "ips",
"redis_name": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"region_ext_id": "region_ext_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
OssTags = map[string]string{
"host": "host",
"host_id": "host_id",
"oss_id": "id",
"oss_ip": "ips",
"oss_name": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"region_ext_id": "region_ext_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
ElbTags = map[string]string{
"host": "host",
"host_id": "host_id",
"elb_id": "id",
"elb_ip": "ips",
"elb_name": "name",
"zone": "zone",
"zone_id": "zone_id",
"zone_ext_id": "zone_ext_id",
"os_type": "os_type",
"status": "status",
"region": "region",
"cloudregion": "cloudregion",
"cloudregion_id": "cloudregion_id",
"tenant": "tenant",
"tenant_id": "tenant_id",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
CloudAccountTags = map[string]string{
"cloudaccount_id": "id",
"cloudaccount_name": "name",
"brand": "brand",
"domain_id": "domain_id",
"project_domain": "project_domain",
}
)

View File

@@ -233,12 +233,6 @@ func (c *QueryCondition) NewEvalMatch(context *alerting.EvalContext, series tsdb
queryKeyInfo = evalMatch.Metric
}
evalMatch.Unit = alertDetails.FieldDescription.Unit
msg := fmt.Sprintf("%s.%s %s %s", alertDetails.Measurement, alertDetails.Field,
alertDetails.Comparator, alerting.RationalizeValueFromUnit(alertDetails.Threshold, evalMatch.Unit, ""))
if len(context.Rule.Message) == 0 {
context.Rule.Message = msg
}
//evalMatch.Condition = c.GenerateFormatCond(meta, queryKeyInfo).String()
evalMatch.Tags = c.filterTags(series.Tags, *alertDetails)
evalMatch.Value = value
evalMatch.ValueStr = alerting.RationalizeValueFromUnit(*value, alertDetails.FieldDescription.Unit,
@@ -246,7 +240,14 @@ func (c *QueryCondition) NewEvalMatch(context *alerting.EvalContext, series tsdb
if alertDetails.GetPointStr {
evalMatch.ValueStr = c.jointPointStr(series, evalMatch.ValueStr, valStrArr)
}
c.FetchCustomizeEvalMatch(context, evalMatch, alertDetails)
//c.newRuleDescription(context, alertDetails)
//evalMatch.Condition = c.GenerateFormatCond(meta, queryKeyInfo).String()
msg := fmt.Sprintf("%s.%s %s %s", alertDetails.Measurement, alertDetails.Field,
alertDetails.Comparator, alerting.RationalizeValueFromUnit(alertDetails.Threshold, evalMatch.Unit, ""))
if len(context.Rule.Message) == 0 {
context.Rule.Message = msg
}
return evalMatch, nil
}
@@ -271,7 +272,8 @@ func (m *meterFetchImp) FetchCustomizeEvalMatch(context *alerting.EvalContext, e
if err != nil {
return err
}
evalMatch.ValueStr = evalMatch.ValueStr + " " + meterCustomizeConfig.UnitDesc
//evalMatch.ValueStr = evalMatch.ValueStr + " " + meterCustomizeConfig.UnitDesc
evalMatch.Unit = meterCustomizeConfig.UnitDesc
return nil
}

View File

@@ -103,11 +103,6 @@ func (n *NotifierBase) ShouldNotify(_ context.Context, evalCtx *alerting.EvalCon
return false
}
// Do not notify when we become Pending for the first
if prevState == monitor.AlertStatePending && newState == monitor.AlertStatePending {
return false
}
// Do not notify when we become OK from pending
if prevState == monitor.AlertStatePending && okOrPending {
return false

View File

@@ -358,8 +358,15 @@ func (manager *SAlertRecordManager) getNowAlertingRecord(ctx context.Context, us
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(context.Background(), jsonutils.Marshal(&input))
if err != nil {
return nil, errors.Wrap(err, "FetchOwnerId error")
}
if ownerId == nil {
ownerId = userCred
}
query := manager.Query()
query = manager.FilterByOwner(query, userCred, rbacutils.String2Scope(input.Scope))
query = manager.FilterByOwner(query, ownerId, rbacutils.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")
@@ -373,7 +380,7 @@ func (manager *SAlertRecordManager) getNowAlertingRecord(ctx context.Context, us
alertsQuery = CommonAlertManager.FilterByOwner(alertsQuery, userCred, rbacutils.String2Scope(input.Scope))
alerts := make([]SCommonAlert, 0)
records := make([]SAlertRecord, 0)
err := db.FetchModelObjects(CommonAlertManager, alertsQuery, &alerts)
err = db.FetchModelObjects(CommonAlertManager, alertsQuery, &alerts)
if err != nil {
return nil, err
}

View File

@@ -487,6 +487,9 @@ func (alert *SCommonAlert) GetMoreDetails(ctx context.Context, out monitor.Commo
if settings.Channel != monitor.DEFAULT_SEND_NOTIFY_CHANNEL {
channel.Insert(settings.Channel)
}
if noti.Frequency != 0 {
out.SilentPeriod = fmt.Sprintf("%dm", noti.Frequency/60)
}
}
out.Channel = channel.List()
out.Status = alert.GetStatus()
@@ -937,10 +940,10 @@ func (alert *SCommonAlert) customizeDeleteNotis(
if err := conf.CustomizeDelete(ctx, userCred, query, data); err != nil {
return err
}
if err := conf.Delete(ctx, userCred); err != nil {
if err := noti.Detach(ctx, userCred); err != nil {
return err
}
if err := noti.Detach(ctx, userCred); err != nil {
if err := conf.Delete(ctx, userCred); err != nil {
return err
}
}

View File

@@ -229,7 +229,7 @@ func (n *SNotification) ShouldSendNotification() bool {
if n.Frequency == 0 {
return true
}
if int64(time.Now().Sub(n.LastSendNotification)/time.Second) >= n.Frequency {
if int64(time.Now().Sub(n.LastSendNotification)/time.Second)+int64(time.Second*60) >= n.Frequency {
return true
}
return false