prometheus/alert/alert_rule.go (107 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ package alert import ( "fmt" "github.com/facebookincubator/prometheus-configmanager/restrictor" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/pkg/rulefmt" ) type File struct { RuleGroups []RuleGroup `yaml:"groups"` } // RuleGroup holds the fields in a Prometheus Alert Rule Group type RuleGroup struct { Name string `yaml:"name"` Interval model.Duration `yaml:"interval,omitempty"` Rules []rulefmt.Rule `yaml:"rules"` } func NewFile(tenantID string) *File { return &File{ RuleGroups: []RuleGroup{{ Name: tenantID, }}, } } // Rules returns the rule configs from this file func (f *File) Rules() []rulefmt.Rule { return f.RuleGroups[0].Rules } // GetRule returns the specific rule by name. Nil if it isn't found func (f *File) GetRule(rulename string) *rulefmt.Rule { for _, rule := range f.RuleGroups[0].Rules { if rule.Alert == rulename { return &rule } } return nil } // AddRule appends a new rule to the list of rules in this file func (f *File) AddRule(rule rulefmt.Rule) { f.RuleGroups[0].Rules = append(f.RuleGroups[0].Rules, rule) } // ReplaceRule replaces an existing rule. Returns error if rule does not // exist already func (f *File) ReplaceRule(newRule rulefmt.Rule) error { ruleIdx := -1 for idx, rule := range f.RuleGroups[0].Rules { if rule.Alert == newRule.Alert { ruleIdx = idx } } if ruleIdx < 0 { return fmt.Errorf("rule %s does not exist", newRule.Alert) } f.RuleGroups[0].Rules[ruleIdx] = newRule return nil } func (f *File) DeleteRule(name string) error { rules := f.RuleGroups[0].Rules for idx, rule := range rules { if rule.Alert == name { f.RuleGroups[0].Rules = append(rules[:idx], rules[idx+1:]...) return nil } } return fmt.Errorf("alert with name %s not found", name) } // SecureRule attaches a label for tenantID to the given alert expression to // to ensure that only metrics owned by this tenant can be alerted on func SecureRule(restrictQueries bool, matcherName, matcherValue string, rule *rulefmt.Rule) error { expr := rule.Expr var err error if restrictQueries { queryRestrictor := restrictor.NewQueryRestrictor(restrictor.DefaultOpts).AddMatcher(matcherName, matcherValue) expr, err = queryRestrictor.RestrictQuery(rule.Expr) if err != nil { return err } } rule.Expr = expr if rule.Labels == nil { rule.Labels = make(map[string]string) } rule.Labels[matcherName] = matcherValue return nil } // RuleJSONWrapper Provides a struct to marshal/unmarshal into a rulefmt.Rule // since rulefmt does not support json encoding type RuleJSONWrapper struct { Record string `json:"record,omitempty"` Alert string `json:"alert,omitempty"` Expr string `json:"expr"` For string `json:"for,omitempty"` Labels map[string]string `json:"labels,omitempty"` Annotations map[string]string `json:"annotations,omitempty"` } func (r *RuleJSONWrapper) ToRuleFmt() (rulefmt.Rule, error) { if r.Labels == nil { r.Labels = make(map[string]string) } if r.Annotations == nil { r.Annotations = make(map[string]string) } rule := rulefmt.Rule{ Record: r.Record, Alert: r.Alert, Expr: r.Expr, Labels: r.Labels, Annotations: r.Annotations, } if r.For != "" { modelFor, err := model.ParseDuration(r.For) if err != nil { return rulefmt.Rule{}, err } rule.For = modelFor } return rule, nil }