mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
10 KiB
399 lines
10 KiB
// Copyright 2015 The Prometheus Authors |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package promql |
|
|
|
import ( |
|
"fmt" |
|
"reflect" |
|
"sort" |
|
"strings" |
|
|
|
clientmodel "github.com/prometheus/client_golang/model" |
|
|
|
"github.com/prometheus/prometheus/storage/metric" |
|
"github.com/prometheus/prometheus/utility" |
|
) |
|
|
|
func (matrix Matrix) String() string { |
|
metricStrings := make([]string, 0, len(matrix)) |
|
for _, sampleStream := range matrix { |
|
metricName, hasName := sampleStream.Metric.Metric[clientmodel.MetricNameLabel] |
|
numLabels := len(sampleStream.Metric.Metric) |
|
if hasName { |
|
numLabels-- |
|
} |
|
labelStrings := make([]string, 0, numLabels) |
|
for label, value := range sampleStream.Metric.Metric { |
|
if label != clientmodel.MetricNameLabel { |
|
labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) |
|
} |
|
} |
|
sort.Strings(labelStrings) |
|
valueStrings := make([]string, 0, len(sampleStream.Values)) |
|
for _, value := range sampleStream.Values { |
|
valueStrings = append(valueStrings, |
|
fmt.Sprintf("\n%v @[%v]", value.Value, value.Timestamp)) |
|
} |
|
metricStrings = append(metricStrings, |
|
fmt.Sprintf("%s{%s} => %s", |
|
metricName, |
|
strings.Join(labelStrings, ", "), |
|
strings.Join(valueStrings, ", "))) |
|
} |
|
sort.Strings(metricStrings) |
|
return strings.Join(metricStrings, "\n") |
|
} |
|
|
|
func (vector Vector) String() string { |
|
metricStrings := make([]string, 0, len(vector)) |
|
for _, sample := range vector { |
|
metricStrings = append(metricStrings, |
|
fmt.Sprintf("%s => %v @[%v]", |
|
sample.Metric, |
|
sample.Value, sample.Timestamp)) |
|
} |
|
return strings.Join(metricStrings, "\n") |
|
} |
|
|
|
// Tree returns a string of the tree structure of the given node. |
|
func Tree(node Node) string { |
|
return tree(node, "") |
|
} |
|
|
|
func tree(node Node, level string) string { |
|
if node == nil { |
|
return fmt.Sprintf("%s |---- %T\n", level, node) |
|
} |
|
typs := strings.Split(fmt.Sprintf("%T", node), ".")[1] |
|
|
|
var t string |
|
// Only print the number of statements for readability. |
|
if stmts, ok := node.(Statements); ok { |
|
t = fmt.Sprintf("%s |---- %s :: %d\n", level, typs, len(stmts)) |
|
} else { |
|
t = fmt.Sprintf("%s |---- %s :: %s\n", level, typs, node) |
|
} |
|
|
|
level += " · · ·" |
|
|
|
switch n := node.(type) { |
|
case Statements: |
|
for _, s := range n { |
|
t += tree(s, level) |
|
} |
|
case *AlertStmt: |
|
t += tree(n.Expr, level) |
|
|
|
case *EvalStmt: |
|
t += tree(n.Expr, level) |
|
|
|
case *RecordStmt: |
|
t += tree(n.Expr, level) |
|
|
|
case Expressions: |
|
for _, e := range n { |
|
t += tree(e, level) |
|
} |
|
case *AggregateExpr: |
|
t += tree(n.Expr, level) |
|
|
|
case *BinaryExpr: |
|
t += tree(n.LHS, level) |
|
t += tree(n.RHS, level) |
|
|
|
case *Call: |
|
t += tree(n.Args, level) |
|
|
|
case *ParenExpr: |
|
t += tree(n.Expr, level) |
|
|
|
case *UnaryExpr: |
|
t += tree(n.Expr, level) |
|
|
|
case *MatrixSelector, *NumberLiteral, *StringLiteral, *VectorSelector: |
|
// nothing to do |
|
|
|
default: |
|
panic("promql.Tree: not all node types covered") |
|
} |
|
return t |
|
} |
|
|
|
func (stmts Statements) String() (s string) { |
|
if len(stmts) == 0 { |
|
return "" |
|
} |
|
for _, stmt := range stmts { |
|
s += stmt.String() |
|
s += "\n\n" |
|
} |
|
return s[:len(s)-2] |
|
} |
|
|
|
func (node *AlertStmt) String() string { |
|
s := fmt.Sprintf("ALERT %s", node.Name) |
|
s += fmt.Sprintf("\n\tIF %s", node.Expr) |
|
if node.Duration > 0 { |
|
s += fmt.Sprintf("\n\tFOR %s", utility.DurationToString(node.Duration)) |
|
} |
|
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) |
|
return s |
|
} |
|
|
|
func (node *EvalStmt) String() string { |
|
return "EVAL " + node.Expr.String() |
|
} |
|
|
|
func (node *RecordStmt) String() string { |
|
s := fmt.Sprintf("%s%s = %s", node.Name, node.Labels, node.Expr) |
|
return s |
|
} |
|
|
|
func (es Expressions) String() (s string) { |
|
if len(es) == 0 { |
|
return "" |
|
} |
|
for _, e := range es { |
|
s += e.String() |
|
s += ", " |
|
} |
|
return s[:len(s)-2] |
|
} |
|
|
|
func (node *AggregateExpr) String() string { |
|
aggrString := fmt.Sprintf("%s(%s)", node.Op, node.Expr) |
|
if len(node.Grouping) > 0 { |
|
return fmt.Sprintf("%s BY (%s)", aggrString, node.Grouping) |
|
} |
|
return aggrString |
|
} |
|
|
|
func (node *BinaryExpr) String() string { |
|
matching := "" |
|
vm := node.VectorMatching |
|
if vm != nil && len(vm.On) > 0 { |
|
matching = fmt.Sprintf(" ON(%s)", vm.On) |
|
if vm.Card == CardManyToOne { |
|
matching += fmt.Sprintf(" GROUP_LEFT(%s)", vm.Include) |
|
} |
|
if vm.Card == CardOneToMany { |
|
matching += fmt.Sprintf(" GROUP_RIGHT(%s)", vm.Include) |
|
} |
|
} |
|
return fmt.Sprintf("%s %s%s %s", node.LHS, node.Op, matching, node.RHS) |
|
} |
|
|
|
func (node *Call) String() string { |
|
return fmt.Sprintf("%s(%s)", node.Func.Name, node.Args) |
|
} |
|
|
|
func (node *MatrixSelector) String() string { |
|
vecSelector := &VectorSelector{ |
|
Name: node.Name, |
|
LabelMatchers: node.LabelMatchers, |
|
} |
|
return fmt.Sprintf("%s[%s]", vecSelector.String(), utility.DurationToString(node.Range)) |
|
} |
|
|
|
func (node *NumberLiteral) String() string { |
|
return fmt.Sprint(node.Val) |
|
} |
|
|
|
func (node *ParenExpr) String() string { |
|
return fmt.Sprintf("(%s)", node.Expr) |
|
} |
|
|
|
func (node *StringLiteral) String() string { |
|
return fmt.Sprintf("%q", node.Val) |
|
} |
|
|
|
func (node *UnaryExpr) String() string { |
|
return fmt.Sprintf("%s%s", node.Op, node.Expr) |
|
} |
|
|
|
func (node *VectorSelector) String() string { |
|
labelStrings := make([]string, 0, len(node.LabelMatchers)-1) |
|
for _, matcher := range node.LabelMatchers { |
|
// Only include the __name__ label if its no equality matching. |
|
if matcher.Name == clientmodel.MetricNameLabel && matcher.Type == metric.Equal { |
|
continue |
|
} |
|
labelStrings = append(labelStrings, matcher.String()) |
|
} |
|
|
|
if len(labelStrings) == 0 { |
|
return node.Name |
|
} |
|
sort.Strings(labelStrings) |
|
return fmt.Sprintf("%s{%s}", node.Name, strings.Join(labelStrings, ",")) |
|
} |
|
|
|
// DotGraph returns a DOT representation of a statement list. |
|
func (ss Statements) DotGraph() string { |
|
graph := "" |
|
for _, stmt := range ss { |
|
graph += stmt.DotGraph() |
|
} |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the alert statement. |
|
func (node *AlertStmt) DotGraph() string { |
|
graph := fmt.Sprintf( |
|
`digraph "Alert Statement" { |
|
%#p[shape="box",label="ALERT %s IF FOR %s"]; |
|
%#p -> %x; |
|
%s |
|
}`, |
|
node, node.Name, utility.DurationToString(node.Duration), |
|
node, reflect.ValueOf(node.Expr).Pointer(), |
|
node.Expr.DotGraph(), |
|
) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the eval statement. |
|
func (node *EvalStmt) DotGraph() string { |
|
graph := fmt.Sprintf( |
|
`%#p[shape="box",label="[%d:%s:%d]"; |
|
%#p -> %x; |
|
%s |
|
}`, |
|
node, node.Start, node.End, node.Interval, |
|
node, reflect.ValueOf(node.Expr).Pointer(), |
|
node.Expr.DotGraph(), |
|
) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the record statement. |
|
func (node *RecordStmt) DotGraph() string { |
|
graph := fmt.Sprintf( |
|
`%#p[shape="box",label="%s = "]; |
|
%#p -> %x; |
|
%s |
|
}`, |
|
node, node.Name, |
|
node, reflect.ValueOf(node.Expr).Pointer(), |
|
node.Expr.DotGraph(), |
|
) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of // DotGraph returns a DOT representation of the record statement. |
|
// DotGraph returns a DOT representation of a statement list. |
|
func (es Expressions) DotGraph() string { |
|
graph := "" |
|
for _, expr := range es { |
|
graph += expr.DotGraph() |
|
} |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the vector aggregation. |
|
func (node *AggregateExpr) DotGraph() string { |
|
groupByStrings := make([]string, 0, len(node.Grouping)) |
|
for _, label := range node.Grouping { |
|
groupByStrings = append(groupByStrings, string(label)) |
|
} |
|
|
|
graph := fmt.Sprintf("%#p[label=\"%s BY (%s)\"]\n", |
|
node, |
|
node.Op, |
|
strings.Join(groupByStrings, ", ")) |
|
graph += fmt.Sprintf("%#p -> %x;\n", node, reflect.ValueOf(node.Expr).Pointer()) |
|
graph += node.Expr.DotGraph() |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the expression. |
|
func (node *BinaryExpr) DotGraph() string { |
|
nodeAddr := reflect.ValueOf(node).Pointer() |
|
graph := fmt.Sprintf( |
|
` |
|
%x[label="%s"]; |
|
%x -> %x; |
|
%x -> %x; |
|
%s |
|
%s |
|
}`, |
|
nodeAddr, node.Op, |
|
nodeAddr, reflect.ValueOf(node.LHS).Pointer(), |
|
nodeAddr, reflect.ValueOf(node.RHS).Pointer(), |
|
node.LHS.DotGraph(), |
|
node.RHS.DotGraph(), |
|
) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the function call. |
|
func (node *Call) DotGraph() string { |
|
graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.Func.Name) |
|
graph += functionArgsToDotGraph(node, node.Args) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the number literal. |
|
func (node *NumberLiteral) DotGraph() string { |
|
return fmt.Sprintf("%#p[label=\"%v\"];\n", node, node.Val) |
|
} |
|
|
|
// DotGraph returns a DOT representation of the encapsulated expression. |
|
func (node *ParenExpr) DotGraph() string { |
|
return node.Expr.DotGraph() |
|
} |
|
|
|
// DotGraph returns a DOT representation of the matrix selector. |
|
func (node *MatrixSelector) DotGraph() string { |
|
return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node) |
|
} |
|
|
|
// DotGraph returns a DOT representation of the string literal. |
|
func (node *StringLiteral) DotGraph() string { |
|
return fmt.Sprintf("%#p[label=\"'%q'\"];\n", node, node.Val) |
|
} |
|
|
|
// DotGraph returns a DOT representation of the unary expression. |
|
func (node *UnaryExpr) DotGraph() string { |
|
nodeAddr := reflect.ValueOf(node).Pointer() |
|
graph := fmt.Sprintf( |
|
` |
|
%x[label="%s"]; |
|
%x -> %x; |
|
%s |
|
%s |
|
}`, |
|
nodeAddr, node.Op, |
|
nodeAddr, reflect.ValueOf(node.Expr).Pointer(), |
|
node.Expr.DotGraph(), |
|
) |
|
return graph |
|
} |
|
|
|
// DotGraph returns a DOT representation of the vector selector. |
|
func (node *VectorSelector) DotGraph() string { |
|
return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node) |
|
} |
|
|
|
func functionArgsToDotGraph(node Node, args Expressions) string { |
|
graph := args.DotGraph() |
|
for _, arg := range args { |
|
graph += fmt.Sprintf("%x -> %x;\n", reflect.ValueOf(node).Pointer(), reflect.ValueOf(arg).Pointer()) |
|
} |
|
return graph |
|
}
|
|
|