From 74cb676537983ec4ffe69563b17239943fe364df Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Thu, 6 Jun 2013 15:12:37 +0200 Subject: [PATCH] Implement Stringer interface for rules and all their children. --- model/labelname.go | 12 +++++ model/metric.go | 33 +++--------- rules/alerting.go | 4 ++ rules/ast/ast.go | 41 ++++++++------- rules/ast/functions_test.go | 3 +- rules/ast/printer.go | 96 +++++++++++++++++++++++---------- rules/helpers.go | 2 +- rules/parser.y | 7 ++- rules/parser.y.go | 102 ++++++++++++++++++------------------ rules/recording.go | 4 ++ rules/rules.go | 2 + 11 files changed, 177 insertions(+), 129 deletions(-) diff --git a/model/labelname.go b/model/labelname.go index 0590fafe6..b9087efe0 100644 --- a/model/labelname.go +++ b/model/labelname.go @@ -13,6 +13,10 @@ package model +import ( + "strings" +) + const ( // The label name indicating the metric name of a timeseries. MetricNameLabel = LabelName("name") @@ -50,3 +54,11 @@ func (l LabelNames) Less(i, j int) bool { func (l LabelNames) Swap(i, j int) { l[i], l[j] = l[j], l[i] } + +func (l LabelNames) String() string { + labelStrings := make([]string, 0, len(l)) + for _, label := range l { + labelStrings = append(labelStrings, string(label)) + } + return strings.Join(labelStrings, ", ") +} diff --git a/model/metric.go b/model/metric.go index 6103e7bc5..5e9c2171f 100644 --- a/model/metric.go +++ b/model/metric.go @@ -19,6 +19,7 @@ import ( "fmt" dto "github.com/prometheus/prometheus/model/generated" "sort" + "strings" "time" ) @@ -50,36 +51,14 @@ func (l LabelSet) Merge(other LabelSet) LabelSet { } func (l LabelSet) String() string { - var ( - buffer bytes.Buffer - labels LabelNames - labelCount int = len(l) - ) - - for name := range l { - labels = append(labels, name) - } - - sort.Sort(labels) - - fmt.Fprintf(&buffer, "{") - for i := 0; i < labelCount; i++ { - var ( - label = labels[i] - value = l[label] - ) - - switch i { - case labelCount - 1: - fmt.Fprintf(&buffer, "%s=%s", label, value) - default: - fmt.Fprintf(&buffer, "%s=%s, ", label, value) - } + labelStrings := make([]string, 0, len(l)) + for label, value := range l { + labelStrings = append(labelStrings, fmt.Sprintf("%s='%s'", label, value)) } - fmt.Fprintf(&buffer, "}") + sort.Strings(labelStrings) - return buffer.String() + return fmt.Sprintf("{%s}", strings.Join(labelStrings, ", ")) } func (l LabelSet) ToMetric() Metric { diff --git a/rules/alerting.go b/rules/alerting.go index 1ab89f69e..04ff5b05a 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -147,6 +147,10 @@ func (rule AlertingRule) ToDotGraph() string { return graph } +func (rule AlertingRule) String() string { + return fmt.Sprintf("ALERT %s IF %s FOR %s WITH %s\n", rule.name, rule.vector, utility.DurationToString(rule.holdDuration), rule.labels) +} + // Construct a new AlertingRule. func NewAlertingRule(name string, vector ast.VectorNode, holdDuration time.Duration, labels model.LabelSet) *AlertingRule { return &AlertingRule{ diff --git a/rules/ast/ast.go b/rules/ast/ast.go index 2a9c8ace1..1b8eaeed1 100644 --- a/rules/ast/ast.go +++ b/rules/ast/ast.go @@ -85,10 +85,13 @@ const ( // Interfaces. // All node interfaces include the Node interface. +type Nodes []Node + type Node interface { Type() ExprType + Children() Nodes NodeTreeToDotGraph() string - Children() []Node + String() string } // All node types implement one of the following interfaces. The name of the @@ -126,7 +129,7 @@ type ( // A function of numeric return type. ScalarFunctionCall struct { function *Function - args []Node + args Nodes } // An arithmetic expression of numeric type. @@ -151,13 +154,13 @@ type ( // A function of vector return type. VectorFunctionCall struct { function *Function - args []Node + args Nodes } // A vector aggregation with vector return type. VectorAggregation struct { aggrType AggrType - groupBy []model.LabelName + groupBy model.LabelNames vector VectorNode } @@ -194,7 +197,7 @@ type ( // A function of string return type. StringFunctionCall struct { function *Function - args []Node + args Nodes } ) @@ -214,16 +217,16 @@ func (node StringLiteral) Type() ExprType { return STRING } func (node StringFunctionCall) Type() ExprType { return STRING } // Node.Children() methods. -func (node ScalarLiteral) Children() []Node { return []Node{} } -func (node ScalarFunctionCall) Children() []Node { return node.args } -func (node ScalarArithExpr) Children() []Node { return []Node{node.lhs, node.rhs} } -func (node VectorLiteral) Children() []Node { return []Node{} } -func (node VectorFunctionCall) Children() []Node { return node.args } -func (node VectorAggregation) Children() []Node { return []Node{node.vector} } -func (node VectorArithExpr) Children() []Node { return []Node{node.lhs, node.rhs} } -func (node MatrixLiteral) Children() []Node { return []Node{} } -func (node StringLiteral) Children() []Node { return []Node{} } -func (node StringFunctionCall) Children() []Node { return node.args } +func (node ScalarLiteral) Children() Nodes { return Nodes{} } +func (node ScalarFunctionCall) Children() Nodes { return node.args } +func (node ScalarArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} } +func (node VectorLiteral) Children() Nodes { return Nodes{} } +func (node VectorFunctionCall) Children() Nodes { return node.args } +func (node VectorAggregation) Children() Nodes { return Nodes{node.vector} } +func (node VectorArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} } +func (node MatrixLiteral) Children() Nodes { return Nodes{} } +func (node StringLiteral) Children() Nodes { return Nodes{} } +func (node StringFunctionCall) Children() Nodes { return node.args } func (node *ScalarLiteral) Eval(timestamp time.Time, view *viewAdapter) model.SampleValue { return node.value @@ -622,7 +625,7 @@ func NewVectorLiteral(labels model.LabelSet) *VectorLiteral { } } -func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy []model.LabelName) *VectorAggregation { +func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy model.LabelNames) *VectorAggregation { return &VectorAggregation{ aggrType: aggrType, groupBy: groupBy, @@ -630,7 +633,7 @@ func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy []model. } } -func NewFunctionCall(function *Function, args []Node) (Node, error) { +func NewFunctionCall(function *Function, args Nodes) (Node, error) { if err := function.CheckArgTypes(args); err != nil { return nil, err } @@ -654,7 +657,7 @@ func NewFunctionCall(function *Function, args []Node) (Node, error) { panic("Function with invalid return type") } -func nodesHaveTypes(nodes []Node, exprTypes []ExprType) bool { +func nodesHaveTypes(nodes Nodes, exprTypes []ExprType) bool { for _, node := range nodes { correctType := false for _, exprType := range exprTypes { @@ -670,7 +673,7 @@ func nodesHaveTypes(nodes []Node, exprTypes []ExprType) bool { } func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) { - if !nodesHaveTypes([]Node{lhs, rhs}, []ExprType{SCALAR, VECTOR}) { + if !nodesHaveTypes(Nodes{lhs, rhs}, []ExprType{SCALAR, VECTOR}) { return nil, errors.New("Binary operands must be of vector or scalar type") } if lhs.Type() == SCALAR && rhs.Type() == VECTOR { diff --git a/rules/ast/functions_test.go b/rules/ast/functions_test.go index 486d54250..02f3603f0 100644 --- a/rules/ast/functions_test.go +++ b/rules/ast/functions_test.go @@ -23,7 +23,8 @@ type emptyRangeNode struct{} func (node emptyRangeNode) Type() ExprType { return MATRIX } func (node emptyRangeNode) NodeTreeToDotGraph() string { return "" } -func (node emptyRangeNode) Children() []Node { return []Node{} } +func (node emptyRangeNode) String() string { return "" } +func (node emptyRangeNode) Children() Nodes { return Nodes{} } func (node emptyRangeNode) Eval(timestamp time.Time, view *viewAdapter) Matrix { return Matrix{ diff --git a/rules/ast/printer.go b/rules/ast/printer.go index a0c71672c..2223cb8ef 100644 --- a/rules/ast/printer.go +++ b/rules/ast/printer.go @@ -45,6 +45,8 @@ func (opType BinOpType) String() string { NE: "!=", GE: ">=", LE: "<=", + AND: "AND", + OR: "OR", } return opTypeMap[opType] } @@ -71,13 +73,13 @@ func (exprType ExprType) String() string { } func (vector Vector) String() string { - metricStrings := []string{} + metricStrings := make([]string, 0, len(vector)) for _, sample := range vector { metricName, ok := sample.Metric[model.MetricNameLabel] if !ok { panic("Tried to print vector without metric name") } - labelStrings := []string{} + labelStrings := make([]string, 0, len(sample.Metric)-1) for label, value := range sample.Metric { if label != model.MetricNameLabel { // TODO escape special chars in label values here and elsewhere. @@ -95,20 +97,20 @@ func (vector Vector) String() string { } func (matrix Matrix) String() string { - metricStrings := []string{} + metricStrings := make([]string, 0, len(matrix)) for _, sampleSet := range matrix { metricName, ok := sampleSet.Metric[model.MetricNameLabel] if !ok { panic("Tried to print matrix without metric name") } - labelStrings := []string{} + labelStrings := make([]string, 0, len(sampleSet.Metric)-1) for label, value := range sampleSet.Metric { if label != model.MetricNameLabel { labelStrings = append(labelStrings, fmt.Sprintf("%s='%s'", label, value)) } } sort.Strings(labelStrings) - valueStrings := []string{} + valueStrings := make([]string, 0, len(sampleSet.Values)) for _, value := range sampleSet.Values { valueStrings = append(valueStrings, fmt.Sprintf("\n%v @[%v]", value.Value, value.Timestamp)) @@ -204,27 +206,6 @@ func EvalToString(node Node, timestamp time.Time, format OutputFormat, storage * panic("Switch didn't cover all node types") } -func (node *VectorLiteral) String() string { - metricName, ok := node.labels[model.MetricNameLabel] - if !ok { - panic("Tried to print vector without metric name") - } - labelStrings := []string{} - for label, value := range node.labels { - if label != model.MetricNameLabel { - labelStrings = append(labelStrings, fmt.Sprintf("%s='%s'", label, value)) - } - } - sort.Strings(labelStrings) - return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ",")) -} - -func (node *MatrixLiteral) String() string { - vectorString := (&VectorLiteral{labels: node.labels}).String() - intervalString := fmt.Sprintf("['%s']", utility.DurationToString(node.interval)) - return vectorString + intervalString -} - func (node *ScalarLiteral) NodeTreeToDotGraph() string { return fmt.Sprintf("%#p[label=\"%v\"];\n", node, node.value) } @@ -268,7 +249,7 @@ func (node *VectorFunctionCall) NodeTreeToDotGraph() string { } func (node *VectorAggregation) NodeTreeToDotGraph() string { - groupByStrings := []string{} + groupByStrings := make([]string, 0, len(node.groupBy)) for _, label := range node.groupBy { groupByStrings = append(groupByStrings, string(label)) } @@ -306,3 +287,64 @@ func (node *StringFunctionCall) NodeTreeToDotGraph() string { graph += functionArgsToDotGraph(node, node.args) return graph } + +func (nodes Nodes) String() string { + nodeStrings := make([]string, 0, len(nodes)) + for _, node := range nodes { + nodeStrings = append(nodeStrings, node.String()) + } + return strings.Join(nodeStrings, ", ") +} + +func (node *ScalarLiteral) String() string { + return fmt.Sprint(node.value) +} + +func (node *ScalarFunctionCall) String() string { + return fmt.Sprintf("%s(%s)", node.function.name, node.args) +} + +func (node *ScalarArithExpr) String() string { + return fmt.Sprintf("(%s %s %s)", node.lhs, node.opType, node.rhs) +} + +func (node *VectorLiteral) String() string { + metricName, ok := node.labels[model.MetricNameLabel] + if !ok { + panic("Tried to print vector without metric name") + } + labelStrings := make([]string, 0, len(node.labels)-1) + for label, value := range node.labels { + if label != model.MetricNameLabel { + labelStrings = append(labelStrings, fmt.Sprintf("%s='%s'", label, value)) + } + } + sort.Strings(labelStrings) + return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ",")) +} + +func (node *VectorFunctionCall) String() string { + return fmt.Sprintf("%s(%s)", node.function.name, node.args) +} + +func (node *VectorAggregation) String() string { + return fmt.Sprintf("%s(%s) BY (%s)", node.aggrType, node.vector, node.groupBy) +} + +func (node *VectorArithExpr) String() string { + return fmt.Sprintf("(%s %s %s)", node.lhs, node.opType, node.rhs) +} + +func (node *MatrixLiteral) String() string { + vectorString := (&VectorLiteral{labels: node.labels}).String() + intervalString := fmt.Sprintf("[%s]", utility.DurationToString(node.interval)) + return vectorString + intervalString +} + +func (node *StringLiteral) String() string { + return fmt.Sprintf("'%s'", node.str) +} + +func (node *StringFunctionCall) String() string { + return fmt.Sprintf("%s(%s)", node.function.name, node.args) +} diff --git a/rules/helpers.go b/rules/helpers.go index 251867a6d..a3a501f57 100644 --- a/rules/helpers.go +++ b/rules/helpers.go @@ -50,7 +50,7 @@ func NewFunctionCall(name string, args []ast.Node) (ast.Node, error) { return functionCall, nil } -func NewVectorAggregation(aggrTypeStr string, vector ast.Node, groupBy []model.LabelName) (*ast.VectorAggregation, error) { +func NewVectorAggregation(aggrTypeStr string, vector ast.Node, groupBy model.LabelNames) (*ast.VectorAggregation, error) { if _, ok := vector.(ast.VectorNode); !ok { return nil, fmt.Errorf("Operand of %v aggregation must be of vector type", aggrTypeStr) } diff --git a/rules/parser.y b/rules/parser.y index 741a01524..e2a3eefcf 100644 --- a/rules/parser.y +++ b/rules/parser.y @@ -14,7 +14,6 @@ %{ package rules - import "fmt" import "github.com/prometheus/prometheus/model" import "github.com/prometheus/prometheus/rules/ast" %} @@ -25,7 +24,7 @@ ruleNode ast.Node ruleNodeSlice []ast.Node boolean bool - labelNameSlice []model.LabelName + labelNameSlice model.LabelNames labelSet model.LabelSet } @@ -164,13 +163,13 @@ rule_expr : '(' rule_expr ')' ; grouping_opts : - { $$ = []model.LabelName{} } + { $$ = model.LabelNames{} } | GROUP_OP '(' label_list ')' { $$ = $3 } ; label_list : IDENTIFIER - { $$ = []model.LabelName{model.LabelName($1)} } + { $$ = model.LabelNames{model.LabelName($1)} } | label_list ',' IDENTIFIER { $$ = append($$, model.LabelName($3)) } ; diff --git a/rules/parser.y.go b/rules/parser.y.go index 4b549cc63..422247afa 100644 --- a/rules/parser.y.go +++ b/rules/parser.y.go @@ -1,12 +1,13 @@ //line parser.y:15 package rules - - import "fmt" +import __yyfmt__ "fmt" +//line parser.y:15 + import "github.com/prometheus/prometheus/model" import "github.com/prometheus/prometheus/rules/ast" -//line parser.y:22 +//line parser.y:21 type yySymType struct { yys int num model.SampleValue @@ -14,7 +15,7 @@ type yySymType struct { ruleNode ast.Node ruleNodeSlice []ast.Node boolean bool - labelNameSlice []model.LabelName + labelNameSlice model.LabelNames labelSet model.LabelSet } @@ -60,7 +61,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyMaxDepth = 200 -//line parser.y:189 +//line parser.y:188 //line yacctab:1 @@ -182,12 +183,13 @@ type yyLexer interface { const yyFlag = -1000 func yyTokname(c int) string { - if c > 0 && c <= len(yyToknames) { - if yyToknames[c-1] != "" { - return yyToknames[c-1] + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] } } - return fmt.Sprintf("tok-%v", c) + return __yyfmt__.Sprintf("tok-%v", c) } func yyStatname(s int) string { @@ -196,7 +198,7 @@ func yyStatname(s int) string { return yyStatenames[s] } } - return fmt.Sprintf("state-%v", s) + return __yyfmt__.Sprintf("state-%v", s) } func yylex1(lex yyLexer, lval *yySymType) int { @@ -229,7 +231,7 @@ out: c = yyTok2[1] /* unknown char */ } if yyDebug >= 3 { - fmt.Printf("lex %U %s\n", uint(char), yyTokname(c)) + __yyfmt__.Printf("lex %U %s\n", uint(char), yyTokname(c)) } return c } @@ -256,7 +258,7 @@ ret1: yystack: /* put a state and value onto the stack */ if yyDebug >= 4 { - fmt.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) + __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) } yyp++ @@ -325,8 +327,8 @@ yydefault: yylex.Error("syntax error") Nerrs++ if yyDebug >= 1 { - fmt.Printf("%s", yyStatname(yystate)) - fmt.Printf("saw %s\n", yyTokname(yychar)) + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf("saw %s\n", yyTokname(yychar)) } fallthrough @@ -345,7 +347,7 @@ yydefault: /* the current p has no shift on "error", pop stack */ if yyDebug >= 2 { - fmt.Printf("error recovery pops state %d\n", yyS[yyp].yys) + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) } yyp-- } @@ -354,7 +356,7 @@ yydefault: case 3: /* no shift yet; clobber input char */ if yyDebug >= 2 { - fmt.Printf("error recovery discards %s\n", yyTokname(yychar)) + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) } if yychar == yyEofCode { goto ret1 @@ -366,7 +368,7 @@ yydefault: /* reduction by production yyn */ if yyDebug >= 2 { - fmt.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) } yynt := yyn @@ -393,133 +395,133 @@ yydefault: switch yynt { case 5: - //line parser.y:67 + //line parser.y:66 { yylex.(*RulesLexer).parsedExpr = yyS[yypt-0].ruleNode } case 6: - //line parser.y:71 + //line parser.y:70 { rule, err := CreateRecordingRule(yyS[yypt-3].str, yyS[yypt-2].labelSet, yyS[yypt-0].ruleNode, yyS[yypt-4].boolean) if err != nil { yylex.Error(err.Error()); return 1 } yylex.(*RulesLexer).parsedRules = append(yylex.(*RulesLexer).parsedRules, rule) } case 7: - //line parser.y:77 + //line parser.y:76 { rule, err := CreateAlertingRule(yyS[yypt-5].str, yyS[yypt-3].ruleNode, yyS[yypt-2].str, yyS[yypt-0].labelSet) if err != nil { yylex.Error(err.Error()); return 1 } yylex.(*RulesLexer).parsedRules = append(yylex.(*RulesLexer).parsedRules, rule) } case 8: - //line parser.y:85 + //line parser.y:84 { yyVAL.str = "0s" } case 9: - //line parser.y:87 + //line parser.y:86 { yyVAL.str = yyS[yypt-0].str } case 10: - //line parser.y:91 + //line parser.y:90 { yyVAL.boolean = false } case 11: - //line parser.y:93 + //line parser.y:92 { yyVAL.boolean = true } case 12: - //line parser.y:97 + //line parser.y:96 { yyVAL.labelSet = model.LabelSet{} } case 13: - //line parser.y:99 + //line parser.y:98 { yyVAL.labelSet = yyS[yypt-1].labelSet } case 14: - //line parser.y:101 + //line parser.y:100 { yyVAL.labelSet = model.LabelSet{} } case 15: - //line parser.y:104 + //line parser.y:103 { yyVAL.labelSet = yyS[yypt-0].labelSet } case 16: - //line parser.y:106 + //line parser.y:105 { for k, v := range yyS[yypt-0].labelSet { yyVAL.labelSet[k] = v } } case 17: - //line parser.y:110 + //line parser.y:109 { yyVAL.labelSet = model.LabelSet{ model.LabelName(yyS[yypt-2].str): model.LabelValue(yyS[yypt-0].str) } } case 18: - //line parser.y:115 + //line parser.y:114 { yyVAL.ruleNode = yyS[yypt-1].ruleNode } case 19: - //line parser.y:117 + //line parser.y:116 { yyS[yypt-0].labelSet[model.MetricNameLabel] = model.LabelValue(yyS[yypt-1].str); yyVAL.ruleNode = ast.NewVectorLiteral(yyS[yypt-0].labelSet) } case 20: - //line parser.y:119 + //line parser.y:118 { var err error yyVAL.ruleNode, err = NewFunctionCall(yyS[yypt-3].str, yyS[yypt-1].ruleNodeSlice) if err != nil { yylex.Error(err.Error()); return 1 } } case 21: - //line parser.y:125 + //line parser.y:124 { var err error yyVAL.ruleNode, err = NewFunctionCall(yyS[yypt-2].str, []ast.Node{}) if err != nil { yylex.Error(err.Error()); return 1 } } case 22: - //line parser.y:131 + //line parser.y:130 { var err error yyVAL.ruleNode, err = NewMatrix(yyS[yypt-3].ruleNode, yyS[yypt-1].str) if err != nil { yylex.Error(err.Error()); return 1 } } case 23: - //line parser.y:137 + //line parser.y:136 { var err error yyVAL.ruleNode, err = NewVectorAggregation(yyS[yypt-4].str, yyS[yypt-2].ruleNode, yyS[yypt-0].labelNameSlice) if err != nil { yylex.Error(err.Error()); return 1 } } case 24: - //line parser.y:145 + //line parser.y:144 { var err error yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) if err != nil { yylex.Error(err.Error()); return 1 } } case 25: - //line parser.y:151 + //line parser.y:150 { var err error yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) if err != nil { yylex.Error(err.Error()); return 1 } } case 26: - //line parser.y:157 + //line parser.y:156 { var err error yyVAL.ruleNode, err = NewArithExpr(yyS[yypt-1].str, yyS[yypt-2].ruleNode, yyS[yypt-0].ruleNode) if err != nil { yylex.Error(err.Error()); return 1 } } case 27: - //line parser.y:163 + //line parser.y:162 { yyVAL.ruleNode = ast.NewScalarLiteral(yyS[yypt-0].num)} case 28: - //line parser.y:167 - { yyVAL.labelNameSlice = []model.LabelName{} } + //line parser.y:166 + { yyVAL.labelNameSlice = model.LabelNames{} } case 29: - //line parser.y:169 + //line parser.y:168 { yyVAL.labelNameSlice = yyS[yypt-1].labelNameSlice } case 30: - //line parser.y:173 - { yyVAL.labelNameSlice = []model.LabelName{model.LabelName(yyS[yypt-0].str)} } + //line parser.y:172 + { yyVAL.labelNameSlice = model.LabelNames{model.LabelName(yyS[yypt-0].str)} } case 31: - //line parser.y:175 + //line parser.y:174 { yyVAL.labelNameSlice = append(yyVAL.labelNameSlice, model.LabelName(yyS[yypt-0].str)) } case 32: - //line parser.y:179 + //line parser.y:178 { yyVAL.ruleNodeSlice = []ast.Node{yyS[yypt-0].ruleNode} } case 33: - //line parser.y:181 + //line parser.y:180 { yyVAL.ruleNodeSlice = append(yyVAL.ruleNodeSlice, yyS[yypt-0].ruleNode) } case 34: - //line parser.y:185 + //line parser.y:184 { yyVAL.ruleNode = yyS[yypt-0].ruleNode } case 35: - //line parser.y:187 + //line parser.y:186 { yyVAL.ruleNode = ast.NewStringLiteral(yyS[yypt-0].str) } } goto yystack /* stack new state and value */ diff --git a/rules/recording.go b/rules/recording.go index 7088c6d85..81b713749 100644 --- a/rules/recording.go +++ b/rules/recording.go @@ -67,6 +67,10 @@ func (rule RecordingRule) ToDotGraph() string { return graph } +func (rule RecordingRule) String() string { + return fmt.Sprintf("%s%s = %s\n", rule.name, rule.labels, rule.vector) +} + // Construct a new RecordingRule. func NewRecordingRule(name string, labels model.LabelSet, vector ast.VectorNode, permanent bool) *RecordingRule { return &RecordingRule{ diff --git a/rules/rules.go b/rules/rules.go index bbfb69d6a..ea7c31246 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -31,4 +31,6 @@ type Rule interface { Eval(timestamp time.Time, storage *metric.TieredStorage) (ast.Vector, error) // ToDotGraph returns a Graphviz dot graph of the rule. ToDotGraph() string + // String returns a human-readable string representation of the rule. + String() string }