2015-03-30 09:12:51 -07:00
|
|
|
// 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"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2015-11-15 01:26:38 -08:00
|
|
|
"time"
|
2015-03-30 09:12:51 -07:00
|
|
|
|
2015-08-20 08:18:46 -07:00
|
|
|
"github.com/prometheus/common/model"
|
2015-03-30 09:12:51 -07:00
|
|
|
|
|
|
|
"github.com/prometheus/prometheus/storage/metric"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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 {
|
2015-04-29 07:35:18 -07:00
|
|
|
if node == nil {
|
|
|
|
return fmt.Sprintf("%s |---- %T\n", level, node)
|
|
|
|
}
|
2015-03-30 09:12:51 -07:00
|
|
|
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 {
|
2016-01-29 06:23:11 -08:00
|
|
|
s += fmt.Sprintf("\n\tFOR %s", model.Duration(node.Duration))
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
if len(node.Labels) > 0 {
|
2016-01-26 06:45:27 -08:00
|
|
|
s += fmt.Sprintf("\n\tLABELS %s", node.Labels)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
2015-12-11 08:02:34 -08:00
|
|
|
if len(node.Annotations) > 0 {
|
|
|
|
s += fmt.Sprintf("\n\tANNOTATIONS %s", node.Labels)
|
|
|
|
}
|
2015-03-30 09:12:51 -07:00
|
|
|
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 {
|
2016-02-07 10:03:16 -08:00
|
|
|
var format string
|
|
|
|
if node.Without {
|
|
|
|
format = "%s WITHOUT (%s)"
|
|
|
|
} else {
|
|
|
|
format = "%s BY (%s)"
|
|
|
|
}
|
2015-06-12 00:42:36 -07:00
|
|
|
if node.KeepExtraLabels {
|
2015-06-12 05:21:01 -07:00
|
|
|
format += " KEEP_COMMON"
|
2015-06-12 00:42:36 -07:00
|
|
|
}
|
|
|
|
return fmt.Sprintf(format, aggrString, node.Grouping)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
return aggrString
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node *BinaryExpr) String() string {
|
2015-09-09 16:37:05 -07:00
|
|
|
returnBool := ""
|
|
|
|
if node.ReturnBool {
|
|
|
|
returnBool = " BOOL"
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:12:51 -07:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2015-09-09 16:37:05 -07:00
|
|
|
return fmt.Sprintf("%s %s%s%s %s", node.LHS, node.Op, returnBool, matching, node.RHS)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
2015-11-15 01:26:38 -08:00
|
|
|
offset := ""
|
|
|
|
if node.Offset != time.Duration(0) {
|
2016-01-29 06:23:11 -08:00
|
|
|
offset = fmt.Sprintf(" OFFSET %s", model.Duration(node.Offset))
|
2015-11-15 01:26:38 -08:00
|
|
|
}
|
2016-01-29 06:23:11 -08:00
|
|
|
return fmt.Sprintf("%s[%s]%s", vecSelector.String(), model.Duration(node.Range), offset)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2015-03-30 10:13:36 -07:00
|
|
|
return fmt.Sprintf("%q", node.Val)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2015-08-20 08:18:46 -07:00
|
|
|
if matcher.Name == model.MetricNameLabel && matcher.Type == metric.Equal {
|
2015-03-30 09:12:51 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
labelStrings = append(labelStrings, matcher.String())
|
|
|
|
}
|
2015-11-15 01:26:38 -08:00
|
|
|
offset := ""
|
|
|
|
if node.Offset != time.Duration(0) {
|
2016-01-29 06:23:11 -08:00
|
|
|
offset = fmt.Sprintf(" OFFSET %s", model.Duration(node.Offset))
|
2015-11-15 01:26:38 -08:00
|
|
|
}
|
2015-03-30 09:12:51 -07:00
|
|
|
|
|
|
|
if len(labelStrings) == 0 {
|
2015-11-15 01:26:38 -08:00
|
|
|
return fmt.Sprintf("%s%s", node.Name, offset)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|
|
|
|
sort.Strings(labelStrings)
|
2015-11-15 01:26:38 -08:00
|
|
|
return fmt.Sprintf("%s{%s}%s", node.Name, strings.Join(labelStrings, ","), offset)
|
2015-03-30 09:12:51 -07:00
|
|
|
}
|