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.
400 lines
10 KiB
400 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
|
|
}
|