Incorporate PR feedback
* Move fingerprint to Hash() * Move away from tsdb.MultiError * 0777 -> 0666 for files * checkOverflow of extra fields Signed-off-by: Goutham Veeramachaneni <cs14btech11014@iith.ac.in>
This commit is contained in:
parent
dc69645e92
commit
6b70a4d850
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/util/cli"
|
"github.com/prometheus/prometheus/util/cli"
|
||||||
"github.com/prometheus/prometheus/util/promlint"
|
"github.com/prometheus/prometheus/util/promlint"
|
||||||
"github.com/prometheus/tsdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckConfigCmd validates configuration files.
|
// CheckConfigCmd validates configuration files.
|
||||||
|
@ -153,8 +152,11 @@ func CheckRulesCmd(t cli.Term, args ...string) int {
|
||||||
failed := false
|
failed := false
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if n, err := checkRules(t, arg); err != nil {
|
if n, errs := checkRules(t, arg); errs != nil {
|
||||||
t.Errorf(" FAILED: %s", err)
|
t.Errorf(" FAILED:")
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf(e.Error())
|
||||||
|
}
|
||||||
failed = true
|
failed = true
|
||||||
} else {
|
} else {
|
||||||
t.Infof(" SUCCESS: %d rules found", n)
|
t.Infof(" SUCCESS: %d rules found", n)
|
||||||
|
@ -167,18 +169,18 @@ func CheckRulesCmd(t cli.Term, args ...string) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkRules(t cli.Term, filename string) (int, error) {
|
func checkRules(t cli.Term, filename string) (int, []error) {
|
||||||
t.Infof("Checking %s", filename)
|
t.Infof("Checking %s", filename)
|
||||||
|
|
||||||
if stat, err := os.Stat(filename); err != nil {
|
if stat, err := os.Stat(filename); err != nil {
|
||||||
return 0, fmt.Errorf("cannot get file info")
|
return 0, []error{fmt.Errorf("cannot get file info")}
|
||||||
} else if stat.IsDir() {
|
} else if stat.IsDir() {
|
||||||
return 0, fmt.Errorf("is a directory")
|
return 0, []error{fmt.Errorf("is a directory")}
|
||||||
}
|
}
|
||||||
|
|
||||||
rgs, errs := rulefmt.ParseFile(filename)
|
rgs, errs := rulefmt.ParseFile(filename)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return 0, tsdb.MultiError(errs)
|
return 0, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
numRules := 0
|
numRules := 0
|
||||||
|
@ -265,7 +267,7 @@ func updateRules(t cli.Term, filename string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioutil.WriteFile(filename+".yaml", y, 0777)
|
return ioutil.WriteFile(filename+".yaml", y, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkMetricsUsage = strings.TrimSpace(`
|
var checkMetricsUsage = strings.TrimSpace(`
|
||||||
|
@ -329,7 +331,7 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Register("update-rules", &cli.Command{
|
app.Register("update-rules", &cli.Command{
|
||||||
Desc: "update the rules to the new YAML format",
|
Desc: "update rules to the new YAML format",
|
||||||
Run: UpdateRulesCmd,
|
Run: UpdateRulesCmd,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
package rulefmt
|
package rulefmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
@ -37,6 +39,9 @@ func (err *Error) Error() string {
|
||||||
type RuleGroups struct {
|
type RuleGroups struct {
|
||||||
Version int `yaml:"version"`
|
Version int `yaml:"version"`
|
||||||
Groups []RuleGroup `yaml:"groups"`
|
Groups []RuleGroup `yaml:"groups"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates all rules in the rule groups.
|
// Validate validates all rules in the rule groups.
|
||||||
|
@ -58,6 +63,10 @@ func (g *RuleGroups) Validate() (errs []error) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkOverflow(g.XXX, "rule_group"); err != nil {
|
||||||
|
errs = append(errs, errors.Wrapf(err, "Group: %s", g.Name))
|
||||||
|
}
|
||||||
|
|
||||||
set[g.Name] = struct{}{}
|
set[g.Name] = struct{}{}
|
||||||
|
|
||||||
for i, r := range g.Rules {
|
for i, r := range g.Rules {
|
||||||
|
@ -70,6 +79,11 @@ func (g *RuleGroups) Validate() (errs []error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkOverflow(g.XXX, "config_file"); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +92,9 @@ type RuleGroup struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Interval model.Duration `yaml:"interval,omitempty"`
|
Interval model.Duration `yaml:"interval,omitempty"`
|
||||||
Rules []Rule `yaml:"rules"`
|
Rules []Rule `yaml:"rules"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule describes an alerting or recording rule.
|
// Rule describes an alerting or recording rule.
|
||||||
|
@ -88,6 +105,9 @@ type Rule struct {
|
||||||
For model.Duration `yaml:"for,omitempty"`
|
For model.Duration `yaml:"for,omitempty"`
|
||||||
Labels map[string]string `yaml:"labels,omitempty"`
|
Labels map[string]string `yaml:"labels,omitempty"`
|
||||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the rule and return a list of encountered errors.
|
// Validate the rule and return a list of encountered errors.
|
||||||
|
@ -129,9 +149,24 @@ func (r *Rule) Validate() (errs []error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkOverflow(r.XXX, "rule"); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkOverflow(m map[string]interface{}, ctx string) error {
|
||||||
|
if len(m) > 0 {
|
||||||
|
var keys []string
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unknown fields in %s: %s", ctx, strings.Join(keys, ", "))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ParseFile parses the rule file and validates it.
|
// ParseFile parses the rule file and validates it.
|
||||||
func ParseFile(file string) (*RuleGroups, []error) {
|
func ParseFile(file string) (*RuleGroups, []error) {
|
||||||
b, err := ioutil.ReadFile(file)
|
b, err := ioutil.ReadFile(file)
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -26,8 +27,6 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
"github.com/prometheus/common/model"
|
|
||||||
"github.com/prometheus/tsdb"
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/config"
|
"github.com/prometheus/prometheus/config"
|
||||||
|
@ -212,12 +211,13 @@ func (g *Group) stop() {
|
||||||
<-g.terminated
|
<-g.terminated
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) fingerprint() model.Fingerprint {
|
func (g *Group) hash() uint64 {
|
||||||
l := model.LabelSet{
|
l := labels.New(
|
||||||
"name": model.LabelValue(g.name),
|
labels.Label{"name", g.name},
|
||||||
"filename": model.LabelValue(g.file),
|
labels.Label{"file", g.file},
|
||||||
}
|
)
|
||||||
return l.Fingerprint()
|
|
||||||
|
return l.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset returns until the next consistently slotted evaluation interval.
|
// offset returns until the next consistently slotted evaluation interval.
|
||||||
|
@ -226,7 +226,7 @@ func (g *Group) offset() time.Duration {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
base = now - (now % int64(g.interval))
|
base = now - (now % int64(g.interval))
|
||||||
offset = uint64(g.fingerprint()) % uint64(g.interval)
|
offset = g.hash() % uint64(g.interval)
|
||||||
next = base + int64(offset)
|
next = base + int64(offset)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -466,9 +466,13 @@ func (m *Manager) ApplyConfig(conf *config.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// To be replaced with a configurable per-group interval.
|
// To be replaced with a configurable per-group interval.
|
||||||
groups, err := m.loadGroups(time.Duration(conf.GlobalConfig.EvaluationInterval), files...)
|
groups, errs := m.loadGroups(time.Duration(conf.GlobalConfig.EvaluationInterval), files...)
|
||||||
if err != nil {
|
if errs != nil {
|
||||||
return fmt.Errorf("error loading rules, previous rule set restored: %s", err)
|
for _, e := range errs {
|
||||||
|
// TODO(gouthamve): Move to non-global logger.
|
||||||
|
log.Errorln(e)
|
||||||
|
}
|
||||||
|
return errors.New("error loading rules, previous rule set restored")
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
@ -511,13 +515,13 @@ func (m *Manager) ApplyConfig(conf *config.Config) error {
|
||||||
// loadGroups reads groups from a list of files.
|
// loadGroups reads groups from a list of files.
|
||||||
// As there's currently no group syntax a single group named "default" containing
|
// As there's currently no group syntax a single group named "default" containing
|
||||||
// all rules will be returned.
|
// all rules will be returned.
|
||||||
func (m *Manager) loadGroups(interval time.Duration, filenames ...string) (map[string]*Group, error) {
|
func (m *Manager) loadGroups(interval time.Duration, filenames ...string) (map[string]*Group, []error) {
|
||||||
groups := make(map[string]*Group)
|
groups := make(map[string]*Group)
|
||||||
|
|
||||||
for _, fn := range filenames {
|
for _, fn := range filenames {
|
||||||
rgs, errs := rulefmt.ParseFile(fn)
|
rgs, errs := rulefmt.ParseFile(fn)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return nil, tsdb.MultiError(errs)
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rg := range rgs.Groups {
|
for _, rg := range rgs.Groups {
|
||||||
|
@ -530,7 +534,7 @@ func (m *Manager) loadGroups(interval time.Duration, filenames ...string) (map[s
|
||||||
for _, r := range rg.Rules {
|
for _, r := range rg.Rules {
|
||||||
expr, err := promql.ParseExpr(r.Expr)
|
expr, err := promql.ParseExpr(r.Expr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Alert != "" {
|
if r.Alert != "" {
|
||||||
|
|
Loading…
Reference in New Issue