From a53b5570eb7a9cc1659b79a4a3323ca90ab065ed Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 30 May 2024 14:37:21 +0200 Subject: [PATCH] wip --- docs/VictoriaLogs/CHANGELOG.md | 1 + docs/VictoriaLogs/LogsQL.md | 1 + lib/logstorage/pipe_math.go | 16 +++++++++++++++ lib/logstorage/pipe_math_test.go | 34 +++++++++++++++++++++++++++++++ lib/logstorage/pipe_stats_test.go | 6 +++--- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/docs/VictoriaLogs/CHANGELOG.md b/docs/VictoriaLogs/CHANGELOG.md index d02c15869..06b091313 100644 --- a/docs/VictoriaLogs/CHANGELOG.md +++ b/docs/VictoriaLogs/CHANGELOG.md @@ -19,6 +19,7 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta ## tip +* FEATURE: add `default` operator to [`math` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#math-pipe). It allows setting `NaN` result to the given default value. * FEATURE: allow omitting result name in [`stats` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe). In this case the result name is automatically set to string representation of the corresponding [stats function expression](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe-functions). For example, `_time:5m | count(*)` is valid [LogsQL query](https://docs.victoriametrics.com/victorialogs/logsql/) now. It is equivalent to `_time:5m | stats count(*) as "count(*)"`. * BUGFIX: properly calculate the number of matching rows in `* | field_values x | stats count() rows` and in `* | unroll (x) | stats count() rows` queries. diff --git a/docs/VictoriaLogs/LogsQL.md b/docs/VictoriaLogs/LogsQL.md index ea48a5e1c..6a0672c68 100644 --- a/docs/VictoriaLogs/LogsQL.md +++ b/docs/VictoriaLogs/LogsQL.md @@ -1608,6 +1608,7 @@ The following mathematical operations are supported by `math` pipe: - `arg1 / arg2` - divides `arg1` by `arg2` - `arg1 % arg2` - returns the remainder of the division of `arg1` by `arg2` - `arg1 ^ arg2` - returns the power of `arg1` by `arg2` +- `arg1 default arg2` - returns `arg2` if `arg1` equals to `NaN`. - `abs(arg)` - returns an absolute value for the given `arg` - `max(arg1, ..., argN)` - returns the maximum value among the given `arg1`, ..., `argN` - `min(arg1, ..., argN)` - returns the minimum value among the given `arg1`, ..., `argN` diff --git a/lib/logstorage/pipe_math.go b/lib/logstorage/pipe_math.go index 07b66f446..5790ea07f 100644 --- a/lib/logstorage/pipe_math.go +++ b/lib/logstorage/pipe_math.go @@ -161,6 +161,10 @@ var mathBinaryOps = map[string]mathBinaryOp{ priority: 3, f: mathFuncMinus, }, + "default": { + priority: 10, + f: mathFuncDefault, + }, } type mathBinaryOp struct { @@ -700,6 +704,18 @@ func mathFuncPow(result []float64, args [][]float64) { } } +func mathFuncDefault(result []float64, args [][]float64) { + values := args[0] + defaultValues := args[1] + for i := range result { + f := values[i] + if math.IsNaN(f) { + f = defaultValues[i] + } + result[i] = f + } +} + func mathFuncAbs(result []float64, args [][]float64) { arg := args[0] for i := range result { diff --git a/lib/logstorage/pipe_math_test.go b/lib/logstorage/pipe_math_test.go index 66a9da24f..af070a1a8 100644 --- a/lib/logstorage/pipe_math_test.go +++ b/lib/logstorage/pipe_math_test.go @@ -22,6 +22,7 @@ func TestParsePipeMathSuccess(t *testing.T) { f(`math min(3, foo, (1 + bar) / baz) as a, max(a, b) as b, (abs(c) + 5) as d`) f(`math round(foo) as x`) f(`math round(foo, 0.1) as y`) + f(`math (a / b default 10) as z`) } func TestParsePipeMathFailure(t *testing.T) { @@ -63,6 +64,39 @@ func TestPipeMath(t *testing.T) { }, }) + f("math a / b default 10 as c", [][]Field{ + { + {"a", "v1"}, + {"b", "2"}, + {"c", "3"}, + }, + { + {"a", "0"}, + {"b", "0"}, + {"c", "3"}, + }, + { + {"a", "3"}, + {"b", "2"}, + }, + }, [][]Field{ + { + {"a", "v1"}, + {"b", "2"}, + {"c", "10"}, + }, + { + {"a", "0"}, + {"b", "0"}, + {"c", "10"}, + }, + { + {"a", "3"}, + {"b", "2"}, + {"c", "1.5"}, + }, + }) + f("math 1 as a", [][]Field{ { {"a", "v1"}, diff --git a/lib/logstorage/pipe_stats_test.go b/lib/logstorage/pipe_stats_test.go index 5363518db..f6cab5fcf 100644 --- a/lib/logstorage/pipe_stats_test.go +++ b/lib/logstorage/pipe_stats_test.go @@ -39,8 +39,8 @@ func TestPipeStats(t *testing.T) { expectPipeResults(t, pipeStr, rows, rowsExpected) } - // missing 'stats' keyword - f("count(*) as rows", [][]Field{ + // missing 'stats' keyword and resutl name + f("count(*)", [][]Field{ { {"_msg", `abc`}, {"a", `2`}, @@ -56,7 +56,7 @@ func TestPipeStats(t *testing.T) { }, }, [][]Field{ { - {"rows", "3"}, + {`count(*)`, "3"}, }, })