mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Merge pull request #9248 from LeviHarrison/atan2-binary-op
PromQL: Add `atan2` binary operator
This commit is contained in:
commit
f103acd513
|
@ -40,6 +40,16 @@ grouping labels becoming the output label set. The metric name is dropped. Entri
|
||||||
for which no matching entry in the right-hand vector can be found are not part of
|
for which no matching entry in the right-hand vector can be found are not part of
|
||||||
the result.
|
the result.
|
||||||
|
|
||||||
|
### Trigonometric binary operators
|
||||||
|
|
||||||
|
The following trigonometric binary operators, which work in radians, exist in Prometheus:
|
||||||
|
|
||||||
|
* `atan2` (based on https://pkg.go.dev/math#Atan2)
|
||||||
|
|
||||||
|
Trigonometric operators allow trigonometric functions to be executed on two vectors using
|
||||||
|
vector matching, which isn't available with normal functions. They act in the same manner
|
||||||
|
as arithmetic operators.
|
||||||
|
|
||||||
### Comparison binary operators
|
### Comparison binary operators
|
||||||
|
|
||||||
The following binary comparison operators exist in Prometheus:
|
The following binary comparison operators exist in Prometheus:
|
||||||
|
@ -264,7 +274,7 @@ The following list shows the precedence of binary operators in Prometheus, from
|
||||||
highest to lowest.
|
highest to lowest.
|
||||||
|
|
||||||
1. `^`
|
1. `^`
|
||||||
2. `*`, `/`, `%`
|
2. `*`, `/`, `%`, `atan2`
|
||||||
3. `+`, `-`
|
3. `+`, `-`
|
||||||
4. `==`, `!=`, `<=`, `<`, `>=`, `>`
|
4. `==`, `!=`, `<=`, `<`, `>=`, `>`
|
||||||
5. `and`, `unless`
|
5. `and`, `unless`
|
||||||
|
|
|
@ -2116,6 +2116,8 @@ func vectorElemBinop(op parser.ItemType, lhs, rhs float64) (float64, bool) {
|
||||||
return lhs, lhs >= rhs
|
return lhs, lhs >= rhs
|
||||||
case parser.LTE:
|
case parser.LTE:
|
||||||
return lhs, lhs <= rhs
|
return lhs, lhs <= rhs
|
||||||
|
case parser.ATAN2:
|
||||||
|
return math.Atan2(lhs, rhs), true
|
||||||
}
|
}
|
||||||
panic(errors.Errorf("operator %q not allowed for operations between Vectors", op))
|
panic(errors.Errorf("operator %q not allowed for operations between Vectors", op))
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ NEQ_REGEX
|
||||||
POW
|
POW
|
||||||
SUB
|
SUB
|
||||||
AT
|
AT
|
||||||
|
ATAN2
|
||||||
%token operatorsEnd
|
%token operatorsEnd
|
||||||
|
|
||||||
// Aggregators.
|
// Aggregators.
|
||||||
|
@ -156,7 +157,7 @@ START_METRIC_SELECTOR
|
||||||
%left LAND LUNLESS
|
%left LAND LUNLESS
|
||||||
%left EQLC GTE GTR LSS LTE NEQ
|
%left EQLC GTE GTR LSS LTE NEQ
|
||||||
%left ADD SUB
|
%left ADD SUB
|
||||||
%left MUL DIV MOD
|
%left MUL DIV MOD ATAN2
|
||||||
%right POW
|
%right POW
|
||||||
|
|
||||||
// Offset modifiers do not have associativity.
|
// Offset modifiers do not have associativity.
|
||||||
|
@ -237,6 +238,7 @@ aggregate_modifier:
|
||||||
|
|
||||||
// Operator precedence only works if each of those is listed separately.
|
// Operator precedence only works if each of those is listed separately.
|
||||||
binary_expr : expr ADD bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
binary_expr : expr ADD bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
||||||
|
| expr ATAN2 bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
||||||
| expr DIV bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
| expr DIV bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
||||||
| expr EQLC bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
| expr EQLC bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
||||||
| expr GTE bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
| expr GTE bin_modifier expr { $$ = yylex.(*parser).newBinaryExpression($1, $2, $3, $4) }
|
||||||
|
@ -674,7 +676,7 @@ series_value : IDENTIFIER
|
||||||
aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK ;
|
aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK ;
|
||||||
|
|
||||||
// inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name.
|
// inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name.
|
||||||
maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END;
|
maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2;
|
||||||
|
|
||||||
unary_op : ADD | SUB;
|
unary_op : ADD | SUB;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -97,6 +97,7 @@ var key = map[string]ItemType{
|
||||||
"and": LAND,
|
"and": LAND,
|
||||||
"or": LOR,
|
"or": LOR,
|
||||||
"unless": LUNLESS,
|
"unless": LUNLESS,
|
||||||
|
"atan2": ATAN2,
|
||||||
|
|
||||||
// Aggregators.
|
// Aggregators.
|
||||||
"sum": SUM,
|
"sum": SUM,
|
||||||
|
|
|
@ -340,6 +340,10 @@ var tests = []struct {
|
||||||
input: "bool",
|
input: "bool",
|
||||||
expected: []Item{{BOOL, 0, "bool"}},
|
expected: []Item{{BOOL, 0, "bool"}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: "atan2",
|
||||||
|
expected: []Item{{ATAN2, 0, "atan2"}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
14
promql/testdata/operators.test
vendored
14
promql/testdata/operators.test
vendored
|
@ -467,3 +467,17 @@ eval instant at 5m test_total < bool test_smaller
|
||||||
{instance="localhost"} 0
|
{instance="localhost"} 0
|
||||||
|
|
||||||
eval instant at 5m test_total < test_smaller
|
eval instant at 5m test_total < test_smaller
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
# Testing atan2.
|
||||||
|
load 5m
|
||||||
|
trigy{} 10
|
||||||
|
trigx{} 20
|
||||||
|
trigNaN{} NaN
|
||||||
|
|
||||||
|
eval instant at 5m trigy atan2 trigx
|
||||||
|
trigy{} 0.4636476090008061
|
||||||
|
|
||||||
|
eval instant at 5m trigy atan2 trigNaN
|
||||||
|
trigy{} NaN
|
||||||
|
|
|
@ -28,6 +28,7 @@ export const binOpTerms = [
|
||||||
{ label: '<' },
|
{ label: '<' },
|
||||||
{ label: '<=' },
|
{ label: '<=' },
|
||||||
{ label: '!=' },
|
{ label: '!=' },
|
||||||
|
{ label: 'atan2' },
|
||||||
{ label: 'and' },
|
{ label: 'and' },
|
||||||
{ label: 'or' },
|
{ label: 'or' },
|
||||||
{ label: 'unless' },
|
{ label: 'unless' },
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
@precedence {
|
@precedence {
|
||||||
pow @right,
|
pow @right,
|
||||||
mul @left,
|
mul @left
|
||||||
add @left,
|
add @left,
|
||||||
eql @left,
|
eql @left,
|
||||||
and @left,
|
and @left,
|
||||||
|
@ -69,6 +69,7 @@ BinaryExpr {
|
||||||
Expr !mul Mul BinModifiers Expr |
|
Expr !mul Mul BinModifiers Expr |
|
||||||
Expr !mul Div BinModifiers Expr |
|
Expr !mul Div BinModifiers Expr |
|
||||||
Expr !mul Mod BinModifiers Expr |
|
Expr !mul Mod BinModifiers Expr |
|
||||||
|
Expr !mul Atan2 BinModifiers Expr |
|
||||||
Expr !add Add BinModifiers Expr |
|
Expr !add Add BinModifiers Expr |
|
||||||
Expr !add Sub BinModifiers Expr |
|
Expr !add Sub BinModifiers Expr |
|
||||||
Expr !eql Eql BinModifiers Expr |
|
Expr !eql Eql BinModifiers Expr |
|
||||||
|
@ -333,6 +334,7 @@ NumberLiteral {
|
||||||
// Contextual keywords
|
// Contextual keywords
|
||||||
|
|
||||||
@external extend {Identifier} extendIdentifier from "./tokens" {
|
@external extend {Identifier} extendIdentifier from "./tokens" {
|
||||||
|
Atan2,
|
||||||
Avg,
|
Avg,
|
||||||
Bottomk,
|
Bottomk,
|
||||||
Count,
|
Count,
|
||||||
|
|
|
@ -840,3 +840,10 @@ sum:my_metric_name:rate5m
|
||||||
|
|
||||||
==>
|
==>
|
||||||
MetricName(MetricIdentifier(Identifier))
|
MetricName(MetricIdentifier(Identifier))
|
||||||
|
|
||||||
|
# Testing Atan2 inherited precedence level
|
||||||
|
|
||||||
|
1 + foo atan2 bar
|
||||||
|
|
||||||
|
==>
|
||||||
|
PromQL(Expr(BinaryExpr(Expr(NumberLiteral),Add,BinModifiers,Expr(BinaryExpr(Expr(VectorSelector(MetricIdentifier(Identifier))),Atan2,BinModifiers,Expr(VectorSelector(MetricIdentifier(Identifier))))))))
|
|
@ -14,6 +14,7 @@
|
||||||
import {
|
import {
|
||||||
And,
|
And,
|
||||||
Avg,
|
Avg,
|
||||||
|
Atan2,
|
||||||
Bool,
|
Bool,
|
||||||
Bottomk,
|
Bottomk,
|
||||||
By,
|
By,
|
||||||
|
@ -58,6 +59,7 @@ export const specializeIdentifier = (value, stack) => {
|
||||||
|
|
||||||
const contextualKeywordTokens = {
|
const contextualKeywordTokens = {
|
||||||
avg: Avg,
|
avg: Avg,
|
||||||
|
atan2: Atan2,
|
||||||
bottomk: Bottomk,
|
bottomk: Bottomk,
|
||||||
count: Count,
|
count: Count,
|
||||||
count_values: CountValues,
|
count_values: CountValues,
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function promQLLanguage(top: LanguageType): LRLanguage {
|
||||||
'Avg Bottomk Count Count_values Group Max Min Quantile Stddev Stdvar Sum Topk': tags.operatorKeyword,
|
'Avg Bottomk Count Count_values Group Max Min Quantile Stddev Stdvar Sum Topk': tags.operatorKeyword,
|
||||||
'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier,
|
'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier,
|
||||||
'And Unless Or': tags.logicOperator,
|
'And Unless Or': tags.logicOperator,
|
||||||
'Sub Add Mul Mod Div Eql Neq Lte Lss Gte Gtr EqlRegex EqlSingle NeqRegex Pow At': tags.operator,
|
'Sub Add Mul Mod Div Atan2 Eql Neq Lte Lss Gte Gtr EqlRegex EqlSingle NeqRegex Pow At': tags.operator,
|
||||||
UnaryOp: tags.arithmeticOperator,
|
UnaryOp: tags.arithmeticOperator,
|
||||||
'( )': tags.paren,
|
'( )': tags.paren,
|
||||||
'[ ]': tags.squareBracket,
|
'[ ]': tags.squareBracket,
|
||||||
|
|
Loading…
Reference in a new issue