mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-16 08:17:31 -08:00
Merge pull request #2207 from weaveworks/expose-rules
Expose rule & group evaluation
This commit is contained in:
commit
dbd6810ea0
|
@ -146,9 +146,9 @@ func (r *AlertingRule) sample(alert *Alert, ts model.Time, set bool) *model.Samp
|
||||||
// is kept in memory state and consequentally repeatedly sent to the AlertManager.
|
// is kept in memory state and consequentally repeatedly sent to the AlertManager.
|
||||||
const resolvedRetention = 15 * time.Minute
|
const resolvedRetention = 15 * time.Minute
|
||||||
|
|
||||||
// eval evaluates the rule expression and then creates pending alerts and fires
|
// Eval evaluates the rule expression and then creates pending alerts and fires
|
||||||
// or removes previously pending alerts accordingly.
|
// or removes previously pending alerts accordingly.
|
||||||
func (r *AlertingRule) eval(ctx context.Context, ts model.Time, engine *promql.Engine, externalURLPath string) (model.Vector, error) {
|
func (r *AlertingRule) Eval(ctx context.Context, ts model.Time, engine *promql.Engine, externalURLPath string) (model.Vector, error) {
|
||||||
query, err := engine.NewInstantQuery(r.vector.String(), ts)
|
query, err := engine.NewInstantQuery(r.vector.String(), ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -106,7 +106,7 @@ const (
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
Name() string
|
Name() string
|
||||||
// eval evaluates the rule, including any associated recording or alerting actions.
|
// eval evaluates the rule, including any associated recording or alerting actions.
|
||||||
eval(context.Context, model.Time, *promql.Engine, string) (model.Vector, error)
|
Eval(context.Context, model.Time, *promql.Engine, string) (model.Vector, error)
|
||||||
// String returns a human-readable string representation of the rule.
|
// String returns a human-readable string representation of the rule.
|
||||||
String() string
|
String() string
|
||||||
// HTMLSnippet returns a human-readable string representation of the rule,
|
// HTMLSnippet returns a human-readable string representation of the rule,
|
||||||
|
@ -125,9 +125,12 @@ type Group struct {
|
||||||
terminated chan struct{}
|
terminated chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGroup(name string, opts *ManagerOptions) *Group {
|
// NewGroup makes a new Group with the given name, options, and rules.
|
||||||
|
func NewGroup(name string, interval time.Duration, rules []Rule, opts *ManagerOptions) *Group {
|
||||||
return &Group{
|
return &Group{
|
||||||
name: name,
|
name: name,
|
||||||
|
interval: interval,
|
||||||
|
rules: rules,
|
||||||
opts: opts,
|
opts: opts,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
terminated: make(chan struct{}),
|
terminated: make(chan struct{}),
|
||||||
|
@ -151,7 +154,7 @@ func (g *Group) run() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
g.eval()
|
g.Eval()
|
||||||
|
|
||||||
iterationDuration.Observe(time.Since(start).Seconds())
|
iterationDuration.Observe(time.Since(start).Seconds())
|
||||||
}
|
}
|
||||||
|
@ -234,10 +237,10 @@ func typeForRule(r Rule) ruleType {
|
||||||
panic(fmt.Errorf("unknown rule type: %T", r))
|
panic(fmt.Errorf("unknown rule type: %T", r))
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval runs a single evaluation cycle in which all rules are evaluated in parallel.
|
// Eval runs a single evaluation cycle in which all rules are evaluated in parallel.
|
||||||
// In the future a single group will be evaluated sequentially to properly handle
|
// In the future a single group will be evaluated sequentially to properly handle
|
||||||
// rule dependency.
|
// rule dependency.
|
||||||
func (g *Group) eval() {
|
func (g *Group) Eval() {
|
||||||
var (
|
var (
|
||||||
now = model.Now()
|
now = model.Now()
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
@ -257,7 +260,7 @@ func (g *Group) eval() {
|
||||||
|
|
||||||
evalTotal.WithLabelValues(rtyp).Inc()
|
evalTotal.WithLabelValues(rtyp).Inc()
|
||||||
|
|
||||||
vector, err := rule.eval(g.opts.Context, now, g.opts.QueryEngine, g.opts.ExternalURL.Path)
|
vector, err := rule.Eval(g.opts.Context, now, g.opts.QueryEngine, g.opts.ExternalURL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Canceled queries are intentional termination of queries. This normally
|
// Canceled queries are intentional termination of queries. This normally
|
||||||
// happens on shutdown and thus we skip logging of any errors here.
|
// happens on shutdown and thus we skip logging of any errors here.
|
||||||
|
@ -394,7 +397,8 @@ func (m *Manager) ApplyConfig(conf *config.Config) error {
|
||||||
files = append(files, fs...)
|
files = append(files, fs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
groups, err := m.loadGroups(files...)
|
// To be replaced with a configurable per-group interval.
|
||||||
|
groups, err := m.loadGroups(time.Duration(conf.GlobalConfig.EvaluationInterval), files...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error loading rules, previous rule set restored: %s", err)
|
return fmt.Errorf("error loading rules, previous rule set restored: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -402,9 +406,6 @@ func (m *Manager) ApplyConfig(conf *config.Config) error {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
for _, newg := range groups {
|
for _, newg := range groups {
|
||||||
// To be replaced with a configurable per-group interval.
|
|
||||||
newg.interval = time.Duration(conf.GlobalConfig.EvaluationInterval)
|
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
// If there is an old group with the same identifier, stop it and wait for
|
// If there is an old group with the same identifier, stop it and wait for
|
||||||
|
@ -442,14 +443,8 @@ 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(filenames ...string) (map[string]*Group, error) {
|
func (m *Manager) loadGroups(interval time.Duration, filenames ...string) (map[string]*Group, error) {
|
||||||
groups := map[string]*Group{}
|
rules := []Rule{}
|
||||||
|
|
||||||
// Currently there is no group syntax implemented. Thus all rules
|
|
||||||
// are read into a single default group.
|
|
||||||
g := newGroup("default", m.opts)
|
|
||||||
groups[g.name] = g
|
|
||||||
|
|
||||||
for _, fn := range filenames {
|
for _, fn := range filenames {
|
||||||
content, err := ioutil.ReadFile(fn)
|
content, err := ioutil.ReadFile(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -473,10 +468,14 @@ func (m *Manager) loadGroups(filenames ...string) (map[string]*Group, error) {
|
||||||
default:
|
default:
|
||||||
panic("retrieval.Manager.LoadRuleFiles: unknown statement type")
|
panic("retrieval.Manager.LoadRuleFiles: unknown statement type")
|
||||||
}
|
}
|
||||||
g.rules = append(g.rules, rule)
|
rules = append(rules, rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Currently there is no group syntax implemented. Thus all rules
|
||||||
|
// are read into a single default group.
|
||||||
|
g := NewGroup("default", interval, rules, m.opts)
|
||||||
|
groups := map[string]*Group{g.name: g}
|
||||||
return groups, nil
|
return groups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ func TestAlertingRule(t *testing.T) {
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
evalTime := model.Time(0).Add(test.time)
|
evalTime := model.Time(0).Add(test.time)
|
||||||
|
|
||||||
res, err := rule.eval(suite.Context(), evalTime, suite.QueryEngine(), "")
|
res, err := rule.Eval(suite.Context(), evalTime, suite.QueryEngine(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error during alerting rule evaluation: %s", err)
|
t.Fatalf("Error during alerting rule evaluation: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ func (rule RecordingRule) Name() string {
|
||||||
return rule.name
|
return rule.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval evaluates the rule and then overrides the metric names and labels accordingly.
|
// Eval evaluates the rule and then overrides the metric names and labels accordingly.
|
||||||
func (rule RecordingRule) eval(ctx context.Context, timestamp model.Time, engine *promql.Engine, _ string) (model.Vector, error) {
|
func (rule RecordingRule) Eval(ctx context.Context, timestamp model.Time, engine *promql.Engine, _ string) (model.Vector, error) {
|
||||||
query, err := engine.NewInstantQuery(rule.vector.String(), timestamp)
|
query, err := engine.NewInstantQuery(rule.vector.String(), timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -63,7 +63,7 @@ func TestRuleEval(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range suite {
|
for _, test := range suite {
|
||||||
rule := NewRecordingRule(test.name, test.expr, test.labels)
|
rule := NewRecordingRule(test.name, test.expr, test.labels)
|
||||||
result, err := rule.eval(ctx, now, engine, "")
|
result, err := rule.Eval(ctx, now, engine, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error evaluating %s", test.name)
|
t.Fatalf("Error evaluating %s", test.name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue