|
|
|
@ -29,14 +29,12 @@ import (
|
|
|
|
|
"github.com/go-kit/kit/log/level" |
|
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
|
|
|
|
|
|
|
|
"github.com/prometheus/prometheus/notifier" |
|
|
|
|
"github.com/prometheus/prometheus/pkg/labels" |
|
|
|
|
"github.com/prometheus/prometheus/pkg/rulefmt" |
|
|
|
|
"github.com/prometheus/prometheus/pkg/timestamp" |
|
|
|
|
"github.com/prometheus/prometheus/pkg/value" |
|
|
|
|
"github.com/prometheus/prometheus/promql" |
|
|
|
|
"github.com/prometheus/prometheus/storage" |
|
|
|
|
"github.com/prometheus/prometheus/util/strutil" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Constants for instrumentation.
|
|
|
|
@ -192,7 +190,7 @@ func (g *Group) File() string { return g.file }
|
|
|
|
|
// Rules returns the group's rules.
|
|
|
|
|
func (g *Group) Rules() []Rule { return g.rules } |
|
|
|
|
|
|
|
|
|
func (g *Group) run() { |
|
|
|
|
func (g *Group) run(ctx context.Context) { |
|
|
|
|
defer close(g.terminated) |
|
|
|
|
|
|
|
|
|
// Wait an initial amount to have consistently slotted intervals.
|
|
|
|
@ -206,7 +204,7 @@ func (g *Group) run() {
|
|
|
|
|
iterationsScheduled.Inc() |
|
|
|
|
|
|
|
|
|
start := time.Now() |
|
|
|
|
g.Eval(start) |
|
|
|
|
g.Eval(ctx, start) |
|
|
|
|
|
|
|
|
|
iterationDuration.Observe(time.Since(start).Seconds()) |
|
|
|
|
g.SetEvaluationTime(time.Since(start)) |
|
|
|
@ -328,7 +326,7 @@ func typeForRule(r Rule) ruleType {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Eval runs a single evaluation cycle in which all rules are evaluated sequentially.
|
|
|
|
|
func (g *Group) Eval(ts time.Time) { |
|
|
|
|
func (g *Group) Eval(ctx context.Context, ts time.Time) { |
|
|
|
|
for i, rule := range g.rules { |
|
|
|
|
select { |
|
|
|
|
case <-g.done: |
|
|
|
@ -346,7 +344,7 @@ func (g *Group) Eval(ts time.Time) {
|
|
|
|
|
|
|
|
|
|
evalTotal.WithLabelValues(rtyp).Inc() |
|
|
|
|
|
|
|
|
|
vector, err := rule.Eval(g.opts.Context, ts, g.opts.Query, g.opts.ExternalURL) |
|
|
|
|
vector, err := rule.Eval(ctx, ts, g.opts.QueryFunc, g.opts.ExternalURL) |
|
|
|
|
if err != nil { |
|
|
|
|
// Canceled queries are intentional termination of queries. This normally
|
|
|
|
|
// happens on shutdown and thus we skip logging of any errors here.
|
|
|
|
@ -358,7 +356,7 @@ func (g *Group) Eval(ts time.Time) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ar, ok := rule.(*AlertingRule); ok { |
|
|
|
|
g.sendAlerts(ar) |
|
|
|
|
g.opts.NotifyFunc(ctx, ar.vector.String(), ar.currentAlerts()...) |
|
|
|
|
} |
|
|
|
|
var ( |
|
|
|
|
numOutOfOrder = 0 |
|
|
|
@ -418,36 +416,6 @@ func (g *Group) Eval(ts time.Time) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// sendAlerts sends alert notifications for the given rule.
|
|
|
|
|
func (g *Group) sendAlerts(rule *AlertingRule) error { |
|
|
|
|
var alerts []*notifier.Alert |
|
|
|
|
|
|
|
|
|
for _, alert := range rule.currentAlerts() { |
|
|
|
|
// Only send actually firing alerts.
|
|
|
|
|
if alert.State == StatePending { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
a := ¬ifier.Alert{ |
|
|
|
|
StartsAt: alert.ActiveAt.Add(rule.holdDuration), |
|
|
|
|
Labels: alert.Labels, |
|
|
|
|
Annotations: alert.Annotations, |
|
|
|
|
GeneratorURL: g.opts.ExternalURL.String() + strutil.TableLinkForExpression(rule.vector.String()), |
|
|
|
|
} |
|
|
|
|
if !alert.ResolvedAt.IsZero() { |
|
|
|
|
a.EndsAt = alert.ResolvedAt |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
alerts = append(alerts, a) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(alerts) > 0 { |
|
|
|
|
g.opts.Notifier.Send(alerts...) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// The Manager manages recording and alerting rules.
|
|
|
|
|
type Manager struct { |
|
|
|
|
opts *ManagerOptions |
|
|
|
@ -463,12 +431,15 @@ type Appendable interface {
|
|
|
|
|
Appender() (storage.Appender, error) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NotifyFunc sends notifications about a set of alerts generated by the given expression.
|
|
|
|
|
type NotifyFunc func(ctx context.Context, expr string, alerts ...*Alert) error |
|
|
|
|
|
|
|
|
|
// ManagerOptions bundles options for the Manager.
|
|
|
|
|
type ManagerOptions struct { |
|
|
|
|
ExternalURL *url.URL |
|
|
|
|
Query QueryFunc |
|
|
|
|
QueryFunc QueryFunc |
|
|
|
|
NotifyFunc NotifyFunc |
|
|
|
|
Context context.Context |
|
|
|
|
Notifier *notifier.Notifier |
|
|
|
|
Appendable Appendable |
|
|
|
|
Logger log.Logger |
|
|
|
|
} |
|
|
|
@ -539,7 +510,7 @@ func (m *Manager) Update(interval time.Duration, files []string) error {
|
|
|
|
|
// is told to run. This is necessary to avoid running
|
|
|
|
|
// queries against a bootstrapping storage.
|
|
|
|
|
<-m.block |
|
|
|
|
newg.run() |
|
|
|
|
newg.run(m.opts.Context) |
|
|
|
|
}() |
|
|
|
|
wg.Done() |
|
|
|
|
}(newg) |
|
|
|
|