From 624f27f4b6f10baa88aa7c78a3ddd35fd2cd8717 Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Mon, 16 Mar 2015 15:57:47 +0100 Subject: [PATCH] Add ln, log2, log10 and exp functions to the query language. --- rules/ast/functions.go | 68 ++++++++++++++++++++++++++++++ rules/rules_test.go | 93 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/rules/ast/functions.go b/rules/ast/functions.go index 79908cd5b..ea95a1966 100644 --- a/rules/ast/functions.go +++ b/rules/ast/functions.go @@ -456,6 +456,50 @@ func ceilImpl(timestamp clientmodel.Timestamp, args []Node) interface{} { return vector } +// === exp(vector VectorNode) Vector === +func expImpl(timestamp clientmodel.Timestamp, args []Node) interface{} { + n := args[0].(VectorNode) + vector := n.Eval(timestamp) + for _, el := range vector { + el.Metric.Delete(clientmodel.MetricNameLabel) + el.Value = clientmodel.SampleValue(math.Exp(float64(el.Value))) + } + return vector +} + +// === ln(vector VectorNode) Vector === +func lnImpl(timestamp clientmodel.Timestamp, args []Node) interface{} { + n := args[0].(VectorNode) + vector := n.Eval(timestamp) + for _, el := range vector { + el.Metric.Delete(clientmodel.MetricNameLabel) + el.Value = clientmodel.SampleValue(math.Log(float64(el.Value))) + } + return vector +} + +// === log2(vector VectorNode) Vector === +func log2Impl(timestamp clientmodel.Timestamp, args []Node) interface{} { + n := args[0].(VectorNode) + vector := n.Eval(timestamp) + for _, el := range vector { + el.Metric.Delete(clientmodel.MetricNameLabel) + el.Value = clientmodel.SampleValue(math.Log2(float64(el.Value))) + } + return vector +} + +// === log10(vector VectorNode) Vector === +func log10Impl(timestamp clientmodel.Timestamp, args []Node) interface{} { + n := args[0].(VectorNode) + vector := n.Eval(timestamp) + for _, el := range vector { + el.Metric.Delete(clientmodel.MetricNameLabel) + el.Value = clientmodel.SampleValue(math.Log10(float64(el.Value))) + } + return vector +} + // === deriv(node MatrixNode) Vector === func derivImpl(timestamp clientmodel.Timestamp, args []Node) interface{} { matrixNode := args[0].(MatrixNode) @@ -598,6 +642,12 @@ var functions = map[string]*Function{ returnType: VectorType, callFn: dropCommonLabelsImpl, }, + "exp": { + name: "exp", + argTypes: []ExprType{VectorType}, + returnType: VectorType, + callFn: expImpl, + }, "floor": { name: "floor", argTypes: []ExprType{VectorType}, @@ -610,6 +660,24 @@ var functions = map[string]*Function{ returnType: VectorType, callFn: histogramQuantileImpl, }, + "ln": { + name: "ln", + argTypes: []ExprType{VectorType}, + returnType: VectorType, + callFn: lnImpl, + }, + "log10": { + name: "log10", + argTypes: []ExprType{VectorType}, + returnType: VectorType, + callFn: log10Impl, + }, + "log2": { + name: "log2", + argTypes: []ExprType{VectorType}, + returnType: VectorType, + callFn: log2Impl, + }, "max_over_time": { name: "max_over_time", argTypes: []ExprType{MatrixType}, diff --git a/rules/rules_test.go b/rules/rules_test.go index baecc50b7..5966c21ec 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -36,7 +36,7 @@ var ( testEvalTime = testStartTime.Add(testSampleInterval * 10) fixturesPath = "fixtures" - reSample = regexp.MustCompile(`^(.*)(?: \=\>|:) (\-?\d+\.?\d*e?\d*|[+-]Inf|NaN) \@\[(\d+)\]$`) + reSample = regexp.MustCompile(`^(.*)(?: \=\>|:) (\-?\d+\.?\d*(?:e-?\d*)?|[+-]Inf|NaN) \@\[(\d+)\]$`) minNormal = math.Float64frombits(0x0010000000000000) // The smallest positive normal value of type float64. ) @@ -1197,6 +1197,97 @@ func TestExpressions(t *testing.T) { `{group="canary", instance="0", job="api-server"} => NaN @[%v]`, }, }, + { + expr: `exp(vector_matching_a)`, + output: []string{ + `{l="x"} => 22026.465794806718 @[%v]`, + `{l="y"} => 485165195.4097903 @[%v]`, + }, + }, + { + expr: `exp(vector_matching_a - 10)`, + output: []string{ + `{l="y"} => 22026.465794806718 @[%v]`, + `{l="x"} => 1 @[%v]`, + }, + }, + { + expr: `exp(vector_matching_a - 20)`, + output: []string{ + `{l="x"} => 4.5399929762484854e-05 @[%v]`, + `{l="y"} => 1 @[%v]`, + }, + }, + { + expr: `ln(vector_matching_a)`, + output: []string{ + `{l="x"} => 2.302585092994046 @[%v]`, + `{l="y"} => 2.995732273553991 @[%v]`, + }, + }, + { + expr: `ln(vector_matching_a - 10)`, + output: []string{ + `{l="y"} => 2.302585092994046 @[%v]`, + `{l="x"} => -Inf @[%v]`, + }, + }, + { + expr: `ln(vector_matching_a - 20)`, + output: []string{ + `{l="y"} => -Inf @[%v]`, + `{l="x"} => NaN @[%v]`, + }, + }, + { + expr: `exp(ln(vector_matching_a))`, + output: []string{ + `{l="y"} => 20 @[%v]`, + `{l="x"} => 10 @[%v]`, + }, + }, + { + expr: `log2(vector_matching_a)`, + output: []string{ + `{l="x"} => 3.3219280948873626 @[%v]`, + `{l="y"} => 4.321928094887363 @[%v]`, + }, + }, + { + expr: `log2(vector_matching_a - 10)`, + output: []string{ + `{l="y"} => 3.3219280948873626 @[%v]`, + `{l="x"} => -Inf @[%v]`, + }, + }, + { + expr: `log2(vector_matching_a - 20)`, + output: []string{ + `{l="x"} => NaN @[%v]`, + `{l="y"} => -Inf @[%v]`, + }, + }, + { + expr: `log10(vector_matching_a)`, + output: []string{ + `{l="x"} => 1 @[%v]`, + `{l="y"} => 1.301029995663981 @[%v]`, + }, + }, + { + expr: `log10(vector_matching_a - 10)`, + output: []string{ + `{l="y"} => 1 @[%v]`, + `{l="x"} => -Inf @[%v]`, + }, + }, + { + expr: `log10(vector_matching_a - 20)`, + output: []string{ + `{l="x"} => NaN @[%v]`, + `{l="y"} => -Inf @[%v]`, + }, + }, } storage, closer := newTestStorage(t)