diff --git a/promql/ast.go b/promql/ast.go index b54a67f2d..09c6fd44d 100644 --- a/promql/ast.go +++ b/promql/ast.go @@ -59,9 +59,7 @@ type AlertStmt struct { Expr Expr Duration time.Duration Labels model.LabelSet - Summary string - Description string - Runbook string + Annotations model.LabelSet } // EvalStmt holds an expression and information on the range it should diff --git a/promql/lex.go b/promql/lex.go index c2c850f3e..5e71c96a5 100644 --- a/promql/lex.go +++ b/promql/lex.go @@ -154,9 +154,7 @@ const ( itemIf itemFor itemWith - itemSummary - itemRunbook - itemDescription + itemAnnotations itemKeepCommon itemOffset itemBy @@ -186,9 +184,7 @@ var key = map[string]itemType{ "if": itemIf, "for": itemFor, "with": itemWith, - "summary": itemSummary, - "runbook": itemRunbook, - "description": itemDescription, + "annotations": itemAnnotations, "offset": itemOffset, "by": itemBy, "keeping_extra": itemKeepCommon, diff --git a/promql/lex_test.go b/promql/lex_test.go index 40c22de1a..5811b9689 100644 --- a/promql/lex_test.go +++ b/promql/lex_test.go @@ -241,14 +241,8 @@ var tests = []struct { input: "with", expected: []item{{itemWith, 0, "with"}}, }, { - input: "description", - expected: []item{{itemDescription, 0, "description"}}, - }, { - input: "summary", - expected: []item{{itemSummary, 0, "summary"}}, - }, { - input: "runbook", - expected: []item{{itemRunbook, 0, "runbook"}}, + input: "annotations", + expected: []item{{itemAnnotations, 0, "annotations"}}, }, { input: "offset", expected: []item{{itemOffset, 0, "offset"}}, diff --git a/promql/parse.go b/promql/parse.go index c15ee6aed..7e2be267b 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -357,9 +357,9 @@ func (p *parser) stmt() Statement { // alertStmt parses an alert rule. // -// ALERT name IF expr [FOR duration] [WITH label_set] -// SUMMARY "summary" -// DESCRIPTION "description" +// ALERT name IF expr [FOR duration] +// [WITH label_set] +// [ANNOTATIONS label_set] // func (p *parser) alertStmt() *AlertStmt { const ctx = "alert statement" @@ -389,44 +389,10 @@ func (p *parser) alertStmt() *AlertStmt { lset = p.labelSet() } - var ( - 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 = p.unquoteString(p.expect(itemString, ctx).val) - - case itemDescription: - if hasDesc { - p.errorf("description must not be defined twice") - } - hasDesc = true - desc = p.unquoteString(p.expect(itemString, ctx).val) - - case itemRunbook: - if hasRunbook { - p.errorf("runbook must not be defined twice") - } - hasRunbook = true - runbook = p.unquoteString(p.expect(itemString, ctx).val) - - default: - p.backup() - break Loop - } - } - if sum == "" { - p.errorf("alert summary missing") - } - if desc == "" { - p.errorf("alert description missing") + annotations := model.LabelSet{} + if p.peek().typ == itemAnnotations { + p.expect(itemAnnotations, ctx) + annotations = p.labelSet() } return &AlertStmt{ @@ -434,9 +400,7 @@ Loop: Expr: expr, Duration: duration, Labels: lset, - Summary: sum, - Description: desc, - Runbook: runbook, + Annotations: annotations, } } @@ -874,11 +838,20 @@ func (p *parser) labelMatchers(operators ...itemType) metric.LabelMatchers { matchers = append(matchers, m) + if p.peek().typ == itemIdentifier { + p.errorf("missing comma before next identifier %q", p.peek().val) + } + // Terminate list if last matcher. if p.peek().typ != itemComma { break } p.next() + + // Allow comma after each item in a multi-line listing. + if p.peek().typ == itemRightBrace { + break + } } p.expect(itemRightBrace, ctx) diff --git a/promql/parse_test.go b/promql/parse_test.go index ab9b78d03..43b62c8a6 100644 --- a/promql/parse_test.go +++ b/promql/parse_test.go @@ -1153,15 +1153,19 @@ var testStatement = []struct { service = "testservice" # ... more fields here ... } - SUMMARY "Global request rate low" - DESCRIPTION "The global request rate is low" + ANNOTATIONS { + summary = "Global request rate low", + description = "The global request rate is low" + } foo = bar{label1="value1"} ALERT BazAlert IF foo > 10 - DESCRIPTION "BazAlert" - RUNBOOK "http://my.url" - SUMMARY "Baz" + ANNOTATIONS { + description = "BazAlert", + runbook = "http://my.url", + summary = "Baz", + } `, expected: Statements{ &RecordStmt{ @@ -1196,10 +1200,12 @@ var testStatement = []struct { }, RHS: &NumberLiteral{10000}, }}, - Labels: model.LabelSet{"service": "testservice"}, - Duration: 5 * time.Minute, - Summary: "Global request rate low", - Description: "The global request rate is low", + Labels: model.LabelSet{"service": "testservice"}, + Duration: 5 * time.Minute, + Annotations: model.LabelSet{ + "summary": "Global request rate low", + "description": "The global request rate is low", + }, }, &RecordStmt{ Name: "foo", @@ -1224,10 +1230,12 @@ var testStatement = []struct { }, RHS: &NumberLiteral{10}, }, - Labels: model.LabelSet{}, - Summary: "Baz", - Description: "BazAlert", - Runbook: "http://my.url", + Labels: model.LabelSet{}, + Annotations: model.LabelSet{ + "summary": "Baz", + "description": "BazAlert", + "runbook": "http://my.url", + }, }, }, }, { @@ -1248,8 +1256,10 @@ var testStatement = []struct { }, }, { input: `ALERT SomeName IF some_metric > 1 - SUMMARY "Global request rate low" - DESCRIPTION "The global request rate is low" + ANNOTATIONS { + summary = "Global request rate low", + description = "The global request rate is low" + } `, expected: Statements{ &AlertStmt{ @@ -1264,9 +1274,11 @@ var testStatement = []struct { }, RHS: &NumberLiteral{1}, }, - Labels: model.LabelSet{}, - Summary: "Global request rate low", - Description: "The global request rate is low", + Labels: model.LabelSet{}, + Annotations: model.LabelSet{ + "summary": "Global request rate low", + "description": "The global request rate is low", + }, }, }, }, { @@ -1276,8 +1288,10 @@ var testStatement = []struct { service = "testservice" # ... more fields here ... } - SUMMARY "Global request rate low" - DESCRIPTION "The global request rate is low" + ANNOTATIONS { + summary = "Global request rate low" + description = "The global request rate is low" + } `, fail: true, }, { @@ -1323,16 +1337,6 @@ var testStatement = []struct { DESCRIPTION "The global request rate is low" `, fail: true, - }, { - input: `ALERT SomeName IF some_metric > 1 WITH {} - SUMMARY "Global request rate low" - `, - fail: true, - }, { - input: `ALERT SomeName IF some_metric > 1 - DESCRIPTION "The global request rate is low" - `, - fail: true, }, // Fuzzing regression tests. { diff --git a/promql/printer.go b/promql/printer.go index 507518eb3..5b4d1070e 100644 --- a/promql/printer.go +++ b/promql/printer.go @@ -109,8 +109,9 @@ func (node *AlertStmt) String() string { if len(node.Labels) > 0 { s += fmt.Sprintf("\n\tWITH %s", node.Labels) } - s += fmt.Sprintf("\n\tSUMMARY %q", node.Summary) - s += fmt.Sprintf("\n\tDESCRIPTION %q", node.Description) + if len(node.Annotations) > 0 { + s += fmt.Sprintf("\n\tANNOTATIONS %s", node.Labels) + } return s }