This commit is contained in:
Aliaksandr Valialkin 2024-05-30 15:09:39 +02:00
parent b021020e03
commit c75c8d7953
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
3 changed files with 88 additions and 0 deletions

View file

@ -1623,6 +1623,8 @@ The following mathematical operations are supported by `math` pipe:
- `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`
- `exp(arg)` - powers [`e`](https://en.wikipedia.org/wiki/E_(mathematical_constant)) by `arg`.
- `ln(arg)` - returns [natural logarightm](https://en.wikipedia.org/wiki/Natural_logarithm) 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`
- `round(arg)` - returns rounded to integer value for the given `arg`. The `round()` accepts optional `nearest` arg, which allows rounding the number to the given `nearest` multiple.
@ -1631,6 +1633,7 @@ The following mathematical operations are supported by `math` pipe:
Every `argX` argument in every mathematical operation can contain one of the following values:
- The name of [log field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model). For example, `errors_total / requests_total`.
If the log field contains value, which cannot be parsed into [supported numeric value](#numeric-values), then it is replaced with `NaN`.
- Any [supported numeric value](#numeric-values). For example, `response_size_bytes / 1MiB`.
- Another mathematical expression. Optionally, it may be put inside `(...)`. For example, `(a + b) * c`.

View file

@ -479,6 +479,10 @@ func parseMathExprOperand(lex *lexer) (*mathExpr, error) {
switch {
case lex.isKeyword("abs"):
return parseMathExprAbs(lex)
case lex.isKeyword("exp"):
return parseMathExprExp(lex)
case lex.isKeyword("ln"):
return parseMathExprLn(lex)
case lex.isKeyword("max"):
return parseMathExprMax(lex)
case lex.isKeyword("min"):
@ -509,6 +513,28 @@ func parseMathExprAbs(lex *lexer) (*mathExpr, error) {
return me, nil
}
func parseMathExprExp(lex *lexer) (*mathExpr, error) {
me, err := parseMathExprGenericFunc(lex, "exp", mathFuncExp)
if err != nil {
return nil, err
}
if len(me.args) != 1 {
return nil, fmt.Errorf("'exp' function accepts only one arg; got %d args: [%s]", len(me.args), me)
}
return me, nil
}
func parseMathExprLn(lex *lexer) (*mathExpr, error) {
me, err := parseMathExprGenericFunc(lex, "ln", mathFuncLn)
if err != nil {
return nil, err
}
if len(me.args) != 1 {
return nil, fmt.Errorf("'ln' function accepts only one arg; got %d args: [%s]", len(me.args), me)
}
return me, nil
}
func parseMathExprMax(lex *lexer) (*mathExpr, error) {
me, err := parseMathExprGenericFunc(lex, "max", mathFuncMax)
if err != nil {
@ -729,6 +755,20 @@ func mathFuncAbs(result []float64, args [][]float64) {
}
}
func mathFuncExp(result []float64, args [][]float64) {
arg := args[0]
for i := range result {
result[i] = math.Exp(arg[i])
}
}
func mathFuncLn(result []float64, args [][]float64) {
arg := args[0]
for i := range result {
result[i] = math.Log(arg[i])
}
}
func mathFuncUnaryMinus(result []float64, args [][]float64) {
arg := args[0]
for i := range result {

View file

@ -23,6 +23,7 @@ func TestParsePipeMathSuccess(t *testing.T) {
f(`math round(foo) as x`)
f(`math round(foo, 0.1) as y`)
f(`math (a / b default 10) as z`)
f(`math (ln(a) + exp(b)) as x`)
}
func TestParsePipeMathFailure(t *testing.T) {
@ -107,6 +108,50 @@ func TestPipeMath(t *testing.T) {
},
})
f("math round(exp(a), 0.01), round(ln(a), 0.01)", [][]Field{
{
{"a", "v1"},
},
{
{"a", "0"},
},
{
{"a", "1"},
},
{
{"a", "2"},
},
{
{"a", "3"},
},
}, [][]Field{
{
{"a", "v1"},
{"round(exp(a), 0.01)", "NaN"},
{"round(ln(a), 0.01)", "NaN"},
},
{
{"a", "0"},
{"round(exp(a), 0.01)", "1"},
{"round(ln(a), 0.01)", "NaN"},
},
{
{"a", "1"},
{"round(exp(a), 0.01)", "2.72"},
{"round(ln(a), 0.01)", "0"},
},
{
{"a", "2"},
{"round(exp(a), 0.01)", "7.39"},
{"round(ln(a), 0.01)", "0.69"},
},
{
{"a", "3"},
{"round(exp(a), 0.01)", "20.09"},
{"round(ln(a), 0.01)", "1.1"},
},
})
f("math 1 as a", [][]Field{
{
{"a", "v1"},