129 lines
4.3 KiB
Go
129 lines
4.3 KiB
Go
package schedule
|
|
|
|
import (
|
|
"fmt"
|
|
"hash/fnv"
|
|
"sort"
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
)
|
|
|
|
// hashUIDs returns a fnv64 hash of the UIDs for all alert rules.
|
|
// The order of the alert rules does not matter as hashUIDs sorts
|
|
// the UIDs in increasing order.
|
|
func hashUIDs(alertRules []*models.AlertRule) uint64 {
|
|
h := fnv.New64()
|
|
for _, uid := range sortedUIDs(alertRules) {
|
|
// We can ignore err as fnv64 does not return an error
|
|
// nolint:errcheck,gosec
|
|
h.Write([]byte(uid))
|
|
}
|
|
return h.Sum64()
|
|
}
|
|
|
|
// sortedUIDs returns a slice of sorted UIDs.
|
|
func sortedUIDs(alertRules []*models.AlertRule) []string {
|
|
uids := make([]string, 0, len(alertRules))
|
|
for _, alertRule := range alertRules {
|
|
uids = append(uids, alertRule.UID)
|
|
}
|
|
sort.Strings(uids)
|
|
return uids
|
|
}
|
|
|
|
type ruleKey struct {
|
|
orgID int64
|
|
ruleGroup models.AlertRuleGroupKeyWithFolderFullpath
|
|
ruleType models.RuleType
|
|
state string
|
|
}
|
|
|
|
func (sch *schedule) updateRulesMetrics(alertRules []*models.AlertRule) {
|
|
// main rule_group_rules metric labels
|
|
buckets := make(map[ruleKey]int64)
|
|
// gauge for rules with notification settings per org
|
|
orgsNfSettings := make(map[int64]int64)
|
|
// gauge for groups per org
|
|
groupsPerOrg := make(map[int64]map[string]struct{})
|
|
|
|
simplifiedEditorSettingsPerOrg := make(map[int64]map[string]int64) // orgID -> setting -> count
|
|
|
|
for _, rule := range alertRules {
|
|
// Count rules by org, type and state
|
|
state := metrics.AlertRuleActiveLabelValue
|
|
if rule.IsPaused {
|
|
state = metrics.AlertRulePausedLabelValue
|
|
}
|
|
ruleGroup := models.AlertRuleGroupKeyWithFolderFullpath{
|
|
AlertRuleGroupKey: rule.GetGroupKey(),
|
|
FolderFullpath: sch.schedulableAlertRules.folderTitles[rule.GetFolderKey()],
|
|
}
|
|
key := ruleKey{
|
|
orgID: rule.OrgID,
|
|
ruleGroup: ruleGroup,
|
|
ruleType: rule.Type(),
|
|
state: state,
|
|
}
|
|
buckets[key]++
|
|
|
|
// Count rules with notification settings per org
|
|
if len(rule.NotificationSettings) > 0 {
|
|
orgsNfSettings[rule.OrgID]++
|
|
}
|
|
|
|
// Count rules with simplified editor settings per org
|
|
editorSettingsMap := map[string]bool{
|
|
"simplified_query_and_expressions_section": rule.Metadata.EditorSettings.SimplifiedQueryAndExpressionsSection,
|
|
"simplified_notifications_section": rule.Metadata.EditorSettings.SimplifiedNotificationsSection,
|
|
}
|
|
for key, value := range editorSettingsMap {
|
|
if value {
|
|
if _, ok := simplifiedEditorSettingsPerOrg[rule.OrgID]; !ok {
|
|
simplifiedEditorSettingsPerOrg[rule.OrgID] = make(map[string]int64)
|
|
}
|
|
simplifiedEditorSettingsPerOrg[rule.OrgID][key]++
|
|
}
|
|
}
|
|
|
|
// Count groups per org
|
|
orgGroups, ok := groupsPerOrg[rule.OrgID]
|
|
if !ok {
|
|
orgGroups = make(map[string]struct{})
|
|
groupsPerOrg[rule.OrgID] = orgGroups
|
|
}
|
|
orgGroups[rule.RuleGroup] = struct{}{}
|
|
}
|
|
|
|
// Reset metrics to avoid stale data
|
|
sch.metrics.GroupRules.Reset()
|
|
sch.metrics.SimpleNotificationRules.Reset()
|
|
sch.metrics.Groups.Reset()
|
|
sch.metrics.SimplifiedEditorRules.Reset()
|
|
|
|
// Set metrics
|
|
for key, count := range buckets {
|
|
sch.metrics.GroupRules.WithLabelValues(fmt.Sprint(key.orgID), key.ruleType.String(), key.state, makeRuleGroupLabelValue(key.ruleGroup)).Set(float64(count))
|
|
}
|
|
for orgID, numRulesNfSettings := range orgsNfSettings {
|
|
sch.metrics.SimpleNotificationRules.WithLabelValues(fmt.Sprint(orgID)).Set(float64(numRulesNfSettings))
|
|
}
|
|
for orgID, groups := range groupsPerOrg {
|
|
sch.metrics.Groups.WithLabelValues(fmt.Sprint(orgID)).Set(float64(len(groups)))
|
|
}
|
|
for orgID, settings := range simplifiedEditorSettingsPerOrg {
|
|
for setting, count := range settings {
|
|
sch.metrics.SimplifiedEditorRules.WithLabelValues(fmt.Sprint(orgID), setting).Set(float64(count))
|
|
}
|
|
}
|
|
// While these are the rules that we iterate over, at the moment there's no 100% guarantee that they'll be
|
|
// scheduled as rules could be removed before we get a chance to evaluate them.
|
|
sch.metrics.SchedulableAlertRules.Set(float64(len(alertRules)))
|
|
sch.metrics.SchedulableAlertRulesHash.Set(float64(hashUIDs(alertRules)))
|
|
}
|
|
|
|
// makeRuleGroupLabelValue returns a string that can be used as a label (rule_group) value for alert rule group metrics.
|
|
func makeRuleGroupLabelValue(key models.AlertRuleGroupKeyWithFolderFullpath) string {
|
|
return fmt.Sprintf("%s;%s", key.FolderFullpath, key.AlertRuleGroupKey.RuleGroup)
|
|
}
|