356 lines
8.7 KiB
Go
356 lines
8.7 KiB
Go
|
// 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"
|
||
|
)
|
||
|
|
||
|
// 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 {
|
||
|
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.Str)
|
||
|
}
|
||
|
|
||
|
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.Str)
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|