Merge pull request #843 from prometheus/fabxc/runbook

promql: add runbook to alert statement.
This commit is contained in:
Fabian Reinartz 2015-06-25 14:07:45 +02:00
commit c1d37bc55b
10 changed files with 65 additions and 9 deletions

View File

@ -48,6 +48,8 @@ type NotificationReq struct {
Summary string Summary string
// Longer alert description. May contain text/template-style interpolations. // Longer alert description. May contain text/template-style interpolations.
Description string Description string
// A reference to the runbook for the alert.
Runbook string
// Labels associated with this alert notification, including alert name. // Labels associated with this alert notification, including alert name.
Labels clientmodel.LabelSet Labels clientmodel.LabelSet
// Current value of alert // Current value of alert
@ -147,6 +149,7 @@ func (n *NotificationHandler) sendNotifications(reqs NotificationReqs) error {
alerts = append(alerts, map[string]interface{}{ alerts = append(alerts, map[string]interface{}{
"summary": req.Summary, "summary": req.Summary,
"description": req.Description, "description": req.Description,
"runbook": req.Runbook,
"labels": req.Labels, "labels": req.Labels,
"payload": map[string]interface{}{ "payload": map[string]interface{}{
"value": req.Value, "value": req.Value,

View File

@ -43,6 +43,7 @@ type testNotificationScenario struct {
description string description string
summary string summary string
message string message string
runbook string
} }
func (s *testNotificationScenario) test(i int, t *testing.T) { func (s *testNotificationScenario) test(i int, t *testing.T) {
@ -63,6 +64,7 @@ func (s *testNotificationScenario) test(i int, t *testing.T) {
{ {
Summary: s.summary, Summary: s.summary,
Description: s.description, Description: s.description,
Runbook: s.runbook,
Labels: clientmodel.LabelSet{ Labels: clientmodel.LabelSet{
clientmodel.LabelName("instance"): clientmodel.LabelValue("testinstance"), clientmodel.LabelName("instance"): clientmodel.LabelValue("testinstance"),
}, },
@ -85,7 +87,8 @@ func TestNotificationHandler(t *testing.T) {
// Correct message. // Correct message.
summary: "Summary", summary: "Summary",
description: "Description", description: "Description",
message: `[{"description":"Description","labels":{"instance":"testinstance"},"payload":{"activeSince":"0001-01-01T00:00:00Z","alertingRule":"Test rule string","generatorURL":"prometheus_url","value":"0.3333333333333333"},"summary":"Summary"}]`, runbook: "Runbook",
message: `[{"description":"Description","labels":{"instance":"testinstance"},"payload":{"activeSince":"0001-01-01T00:00:00Z","alertingRule":"Test rule string","generatorURL":"prometheus_url","value":"0.3333333333333333"},"runbook":"Runbook","summary":"Summary"}]`,
}, },
} }

View File

@ -62,6 +62,7 @@ type AlertStmt struct {
Labels clientmodel.LabelSet Labels clientmodel.LabelSet
Summary string Summary string
Description string Description string
Runbook string
} }
// EvalStmt holds an expression and information on the range it should // EvalStmt holds an expression and information on the range it should

View File

@ -144,6 +144,7 @@ const (
itemFor itemFor
itemWith itemWith
itemSummary itemSummary
itemRunbook
itemDescription itemDescription
itemKeepCommon itemKeepCommon
itemOffset itemOffset
@ -174,6 +175,7 @@ var key = map[string]itemType{
"for": itemFor, "for": itemFor,
"with": itemWith, "with": itemWith,
"summary": itemSummary, "summary": itemSummary,
"runbook": itemRunbook,
"description": itemDescription, "description": itemDescription,
"offset": itemOffset, "offset": itemOffset,
"by": itemBy, "by": itemBy,

View File

@ -241,6 +241,9 @@ var tests = []struct {
}, { }, {
input: "summary", input: "summary",
expected: []item{{itemSummary, 0, "summary"}}, expected: []item{{itemSummary, 0, "summary"}},
}, {
input: "runbook",
expected: []item{{itemRunbook, 0, "runbook"}},
}, { }, {
input: "offset", input: "offset",
expected: []item{{itemOffset, 0, "offset"}}, expected: []item{{itemOffset, 0, "offset"}},

View File

@ -379,11 +379,45 @@ func (p *parser) alertStmt() *AlertStmt {
lset = p.labelSet() lset = p.labelSet()
} }
p.expect(itemSummary, ctx) var (
sum := trimOne(p.expect(itemString, ctx).val) hasSum, hasDesc, hasRunbook bool
sum, desc, runbook string
)
Loop:
for {
switch p.next().typ {
case itemSummary:
if hasSum {
p.errorf("summary must not be defined twice")
}
hasSum = true
sum = trimOne(p.expect(itemString, ctx).val)
p.expect(itemDescription, ctx) case itemDescription:
desc := trimOne(p.expect(itemString, ctx).val) if hasDesc {
p.errorf("description must not be defined twice")
}
hasDesc = true
desc = trimOne(p.expect(itemString, ctx).val)
case itemRunbook:
if hasRunbook {
p.errorf("runbook must not be defined twice")
}
hasRunbook = true
runbook = trimOne(p.expect(itemString, ctx).val)
default:
p.backup()
break Loop
}
}
if sum == "" {
p.errorf("alert summary missing")
}
if desc == "" {
p.errorf("alert description missing")
}
return &AlertStmt{ return &AlertStmt{
Name: name.val, Name: name.val,
@ -392,6 +426,7 @@ func (p *parser) alertStmt() *AlertStmt {
Labels: lset, Labels: lset,
Summary: sum, Summary: sum,
Description: desc, Description: desc,
Runbook: runbook,
} }
} }

View File

@ -1032,9 +1032,10 @@ var testStatement = []struct {
foo = bar{label1="value1"} foo = bar{label1="value1"}
ALERT BazAlert IF foo > 10 WITH {} ALERT BazAlert IF foo > 10
SUMMARY "Baz"
DESCRIPTION "BazAlert" DESCRIPTION "BazAlert"
RUNBOOK "http://my.url"
SUMMARY "Baz"
`, `,
expected: Statements{ expected: Statements{
&RecordStmt{ &RecordStmt{
@ -1100,6 +1101,7 @@ var testStatement = []struct {
Labels: clientmodel.LabelSet{}, Labels: clientmodel.LabelSet{},
Summary: "Baz", Summary: "Baz",
Description: "BazAlert", Description: "BazAlert",
Runbook: "http://my.url",
}, },
}, },
}, { }, {

View File

@ -112,6 +112,8 @@ type AlertingRule struct {
summary string summary string
// More detailed alert description. // More detailed alert description.
description string description string
// A reference to a runbook for the alert.
runbook string
// Protects the below. // Protects the below.
mutex sync.Mutex mutex sync.Mutex
@ -128,6 +130,7 @@ func NewAlertingRule(
labels clientmodel.LabelSet, labels clientmodel.LabelSet,
summary string, summary string,
description string, description string,
runbook string,
) *AlertingRule { ) *AlertingRule {
return &AlertingRule{ return &AlertingRule{
name: name, name: name,
@ -136,6 +139,7 @@ func NewAlertingRule(
labels: labels, labels: labels,
summary: summary, summary: summary,
description: description, description: description,
runbook: runbook,
activeAlerts: map[clientmodel.Fingerprint]*Alert{}, activeAlerts: map[clientmodel.Fingerprint]*Alert{},
} }
@ -219,6 +223,7 @@ func (rule *AlertingRule) String() string {
} }
s += fmt.Sprintf("\n\tSUMMARY %q", rule.summary) s += fmt.Sprintf("\n\tSUMMARY %q", rule.summary)
s += fmt.Sprintf("\n\tDESCRIPTION %q", rule.description) s += fmt.Sprintf("\n\tDESCRIPTION %q", rule.description)
s += fmt.Sprintf("\n\tRUNBOOK %q", rule.runbook)
return s return s
} }
@ -240,6 +245,7 @@ func (rule *AlertingRule) HTMLSnippet(pathPrefix string) template.HTML {
} }
s += fmt.Sprintf("\n SUMMARY %q", rule.summary) s += fmt.Sprintf("\n SUMMARY %q", rule.summary)
s += fmt.Sprintf("\n DESCRIPTION %q", rule.description) s += fmt.Sprintf("\n DESCRIPTION %q", rule.description)
s += fmt.Sprintf("\n RUNBOOK %q", rule.runbook)
return template.HTML(s) return template.HTML(s)
} }

View File

@ -207,6 +207,7 @@ func (m *Manager) queueAlertNotifications(rule *AlertingRule, timestamp clientmo
notifications = append(notifications, &notification.NotificationReq{ notifications = append(notifications, &notification.NotificationReq{
Summary: expand(rule.summary), Summary: expand(rule.summary),
Description: expand(rule.description), Description: expand(rule.description),
Runbook: rule.runbook,
Labels: aa.Labels.Merge(clientmodel.LabelSet{ Labels: aa.Labels.Merge(clientmodel.LabelSet{
alertNameLabel: clientmodel.LabelValue(rule.Name()), alertNameLabel: clientmodel.LabelValue(rule.Name()),
}), }),
@ -316,7 +317,7 @@ func (m *Manager) loadRuleFiles(filenames ...string) error {
for _, stmt := range stmts { for _, stmt := range stmts {
switch r := stmt.(type) { switch r := stmt.(type) {
case *promql.AlertStmt: case *promql.AlertStmt:
rule := NewAlertingRule(r.Name, r.Expr, r.Duration, r.Labels, r.Summary, r.Description) rule := NewAlertingRule(r.Name, r.Expr, r.Duration, r.Labels, r.Summary, r.Description, r.Runbook)
m.rules = append(m.rules, rule) m.rules = append(m.rules, rule)
case *promql.RecordStmt: case *promql.RecordStmt:
rule := NewRecordingRule(r.Name, r.Expr, r.Labels) rule := NewRecordingRule(r.Name, r.Expr, r.Labels)

View File

@ -181,7 +181,7 @@ func TestAlertingRule(t *testing.T) {
alertLabels := clientmodel.LabelSet{ alertLabels := clientmodel.LabelSet{
"severity": "critical", "severity": "critical",
} }
rule := NewAlertingRule("HttpRequestRateLow", expr, time.Minute, alertLabels, "summary", "description") rule := NewAlertingRule("HttpRequestRateLow", expr, time.Minute, alertLabels, "summary", "description", "runbook")
for i, expectedLines := range evalOutputs { for i, expectedLines := range evalOutputs {
evalTime := testStartTime.Add(testSampleInterval * time.Duration(i)) evalTime := testStartTime.Add(testSampleInterval * time.Duration(i))