Merge pull request #9248 from LeviHarrison/atan2-binary-op

PromQL: Add `atan2` binary operator
pull/9347/head
Julius Volz 2021-09-27 18:45:56 +02:00 committed by GitHub
commit f103acd513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 566 additions and 511 deletions

View File

@ -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
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
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.
1. `^`
2. `*`, `/`, `%`
2. `*`, `/`, `%`, `atan2`
3. `+`, `-`
4. `==`, `!=`, `<=`, `<`, `>=`, `>`
5. `and`, `unless`

View File

@ -2116,6 +2116,8 @@ func vectorElemBinop(op parser.ItemType, lhs, rhs float64) (float64, bool) {
return lhs, lhs >= rhs
case parser.LTE:
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))
}

View File

@ -84,6 +84,7 @@ NEQ_REGEX
POW
SUB
AT
ATAN2
%token operatorsEnd
// Aggregators.
@ -156,7 +157,7 @@ START_METRIC_SELECTOR
%left LAND LUNLESS
%left EQLC GTE GTR LSS LTE NEQ
%left ADD SUB
%left MUL DIV MOD
%left MUL DIV MOD ATAN2
%right POW
// Offset modifiers do not have associativity.
@ -237,6 +238,7 @@ aggregate_modifier:
// 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) }
| 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 EQLC 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 ;
// 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;

File diff suppressed because it is too large Load Diff

View File

@ -97,6 +97,7 @@ var key = map[string]ItemType{
"and": LAND,
"or": LOR,
"unless": LUNLESS,
"atan2": ATAN2,
// Aggregators.
"sum": SUM,

View File

@ -340,6 +340,10 @@ var tests = []struct {
input: "bool",
expected: []Item{{BOOL, 0, "bool"}},
},
{
input: "atan2",
expected: []Item{{ATAN2, 0, "atan2"}},
},
},
},
{

View File

@ -467,3 +467,17 @@ eval instant at 5m test_total < bool test_smaller
{instance="localhost"} 0
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

View File

@ -28,6 +28,7 @@ export const binOpTerms = [
{ label: '<' },
{ label: '<=' },
{ label: '!=' },
{ label: 'atan2' },
{ label: 'and' },
{ label: 'or' },
{ label: 'unless' },

View File

@ -16,7 +16,7 @@
@precedence {
pow @right,
mul @left,
mul @left
add @left,
eql @left,
and @left,
@ -69,6 +69,7 @@ BinaryExpr {
Expr !mul Mul BinModifiers Expr |
Expr !mul Div BinModifiers Expr |
Expr !mul Mod BinModifiers Expr |
Expr !mul Atan2 BinModifiers Expr |
Expr !add Add BinModifiers Expr |
Expr !add Sub BinModifiers Expr |
Expr !eql Eql BinModifiers Expr |
@ -333,6 +334,7 @@ NumberLiteral {
// Contextual keywords
@external extend {Identifier} extendIdentifier from "./tokens" {
Atan2,
Avg,
Bottomk,
Count,

View File

@ -840,3 +840,10 @@ sum:my_metric_name:rate5m
==>
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))))))))

View File

@ -14,6 +14,7 @@
import {
And,
Avg,
Atan2,
Bool,
Bottomk,
By,
@ -58,6 +59,7 @@ export const specializeIdentifier = (value, stack) => {
const contextualKeywordTokens = {
avg: Avg,
atan2: Atan2,
bottomk: Bottomk,
count: Count,
count_values: CountValues,

View File

@ -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,
'By Without Bool On Ignoring GroupLeft GroupRight Offset Start End': tags.modifier,
'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,
'( )': tags.paren,
'[ ]': tags.squareBracket,