mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-27 14:39:40 -08:00
213a8fe89a
* Use generated parser for series descriptions Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
382 lines
12 KiB
Plaintext
382 lines
12 KiB
Plaintext
// Copyright 2019 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
%{
|
|
package promql
|
|
|
|
import (
|
|
"math"
|
|
"sort"
|
|
"strconv"
|
|
|
|
"github.com/prometheus/prometheus/pkg/labels"
|
|
"github.com/prometheus/prometheus/pkg/value"
|
|
)
|
|
%}
|
|
|
|
%union {
|
|
node Node
|
|
item Item
|
|
matchers []*labels.Matcher
|
|
matcher *labels.Matcher
|
|
label labels.Label
|
|
labels labels.Labels
|
|
strings []string
|
|
series []sequenceValue
|
|
uint uint64
|
|
float float64
|
|
}
|
|
|
|
|
|
%token <item> ERROR
|
|
%token <item> EOF
|
|
%token <item> COMMENT
|
|
%token <item> IDENTIFIER
|
|
%token <item> METRIC_IDENTIFIER
|
|
%token <item> LEFT_PAREN
|
|
%token <item> RIGHT_PAREN
|
|
%token <item> LEFT_BRACE
|
|
%token <item> RIGHT_BRACE
|
|
%token <item> LEFT_BRACKET
|
|
%token <item> RIGHT_BRACKET
|
|
%token <item> COMMA
|
|
%token <item> ASSIGN
|
|
%token <item> COLON
|
|
%token <item> SEMICOLON
|
|
%token <item> STRING
|
|
%token <item> NUMBER
|
|
%token <item> DURATION
|
|
%token <item> BLANK
|
|
%token <item> TIMES
|
|
%token <item> SPACE
|
|
|
|
%token operatorsStart
|
|
// Operators.
|
|
%token <item> SUB
|
|
%token <item> ADD
|
|
%token <item> MUL
|
|
%token <item> MOD
|
|
%token <item> DIV
|
|
%token <item> LAND
|
|
%token <item> LOR
|
|
%token <item> LUNLESS
|
|
%token <item> EQL
|
|
%token <item> NEQ
|
|
%token <item> LTE
|
|
%token <item> LSS
|
|
%token <item> GTE
|
|
%token <item> GTR
|
|
%token <item> EQL_REGEX
|
|
%token <item> NEQ_REGEX
|
|
%token <item> POW
|
|
%token operatorsEnd
|
|
|
|
%token aggregatorsStart
|
|
// Aggregators.
|
|
%token <item> AVG
|
|
%token <item> COUNT
|
|
%token <item> SUM
|
|
%token <item> MIN
|
|
%token <item> MAX
|
|
%token <item> STDDEV
|
|
%token <item> STDVAR
|
|
%token <item> TOPK
|
|
%token <item> BOTTOMK
|
|
%token <item> COUNT_VALUES
|
|
%token <item> QUANTILE
|
|
%token aggregatorsEnd
|
|
|
|
%token keywordsStart
|
|
// Keywords.
|
|
%token <item> OFFSET
|
|
%token <item> BY
|
|
%token <item> WITHOUT
|
|
%token <item> ON
|
|
%token <item> IGNORING
|
|
%token <item> GROUP_LEFT
|
|
%token <item> GROUP_RIGHT
|
|
%token <item> BOOL
|
|
|
|
%token keywordsEnd
|
|
|
|
|
|
%token startSymbolsStart
|
|
// Start symbols for the generated parser.
|
|
%token START_LABELS
|
|
%token START_METRIC
|
|
%token START_GROUPING_LABELS
|
|
%token START_SERIES_DESCRIPTION
|
|
%token startSymbolsEnd
|
|
|
|
%type <matchers> label_matchers label_match_list
|
|
%type <matcher> label_matcher
|
|
|
|
%type <item> match_op metric_identifier grouping_label maybe_label
|
|
|
|
%type <labels> label_set_list label_set metric
|
|
%type <label> label_set_item
|
|
%type <strings> grouping_labels grouping_label_list
|
|
%type <series> series_values series_item
|
|
%type <uint> uint
|
|
%type <float> series_value signed_number number
|
|
|
|
%start start
|
|
|
|
%%
|
|
|
|
start : START_LABELS label_matchers
|
|
{yylex.(*parser).generatedParserResult.(*VectorSelector).LabelMatchers = $2}
|
|
| START_METRIC metric
|
|
{ yylex.(*parser).generatedParserResult = $2 }
|
|
| START_GROUPING_LABELS grouping_labels
|
|
{ yylex.(*parser).generatedParserResult = $2 }
|
|
| START_SERIES_DESCRIPTION series_description
|
|
| start EOF
|
|
| error /* If none of the more detailed error messages are triggered, we fall back to this. */
|
|
{ yylex.(*parser).unexpected("","") }
|
|
;
|
|
|
|
|
|
label_matchers :
|
|
LEFT_BRACE label_match_list RIGHT_BRACE
|
|
{ $$ = $2 }
|
|
| LEFT_BRACE label_match_list COMMA RIGHT_BRACE
|
|
{ $$ = $2 }
|
|
| LEFT_BRACE RIGHT_BRACE
|
|
{ $$ = []*labels.Matcher{} }
|
|
|
|
;
|
|
|
|
label_match_list:
|
|
label_match_list COMMA label_matcher
|
|
{ $$ = append($1, $3)}
|
|
| label_matcher
|
|
{ $$ = []*labels.Matcher{$1}}
|
|
| label_match_list error
|
|
{ yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") }
|
|
;
|
|
|
|
label_matcher :
|
|
IDENTIFIER match_op STRING
|
|
{ $$ = yylex.(*parser).newLabelMatcher($1, $2, $3) }
|
|
| IDENTIFIER match_op error
|
|
{ yylex.(*parser).unexpected("label matching", "string")}
|
|
| IDENTIFIER error
|
|
{ yylex.(*parser).unexpected("label matching", "label matching operator") }
|
|
| error
|
|
{ yylex.(*parser).unexpected("label matching", "identifier or \"}\"")}
|
|
;
|
|
|
|
match_op :
|
|
EQL {$$ =$1}
|
|
| NEQ {$$=$1}
|
|
| EQL_REGEX {$$=$1}
|
|
| NEQ_REGEX {$$=$1}
|
|
;
|
|
|
|
|
|
metric :
|
|
metric_identifier label_set
|
|
{ $$ = append($2, labels.Label{Name: labels.MetricName, Value: $1.Val}); sort.Sort($$) }
|
|
| label_set
|
|
{$$ = $1}
|
|
;
|
|
|
|
metric_identifier
|
|
:
|
|
METRIC_IDENTIFIER {$$=$1}
|
|
| IDENTIFIER {$$=$1}
|
|
|
|
label_set :
|
|
LEFT_BRACE label_set_list RIGHT_BRACE
|
|
{ $$ = labels.New($2...) }
|
|
| LEFT_BRACE label_set_list COMMA RIGHT_BRACE
|
|
{ $$ = labels.New($2...) }
|
|
| LEFT_BRACE RIGHT_BRACE
|
|
{ $$ = labels.New() }
|
|
| /* empty */
|
|
{ $$ = labels.New() }
|
|
;
|
|
|
|
label_set_list :
|
|
label_set_list COMMA label_set_item
|
|
{ $$ = append($1, $3) }
|
|
| label_set_item
|
|
{ $$ = []labels.Label{$1} }
|
|
| label_set_list error
|
|
{ yylex.(*parser).unexpected("label set", "\",\" or \"}\"", ) }
|
|
|
|
;
|
|
|
|
label_set_item :
|
|
IDENTIFIER EQL STRING
|
|
{ $$ = labels.Label{Name: $1.Val, Value: yylex.(*parser).unquoteString($3.Val) } }
|
|
| IDENTIFIER EQL error
|
|
{ yylex.(*parser).unexpected("label set", "string")}
|
|
| IDENTIFIER error
|
|
{ yylex.(*parser).unexpected("label set", "\"=\"")}
|
|
| error
|
|
{ yylex.(*parser).unexpected("label set", "identifier or \"}\"") }
|
|
;
|
|
|
|
grouping_labels :
|
|
LEFT_PAREN grouping_label_list RIGHT_PAREN
|
|
{ $$ = $2 }
|
|
| LEFT_PAREN grouping_label_list COMMA RIGHT_PAREN
|
|
{ $$ = $2 }
|
|
| LEFT_PAREN RIGHT_PAREN
|
|
{ $$ = []string{} }
|
|
| error
|
|
{ yylex.(*parser).unexpected("grouping opts", "\"(\"") }
|
|
;
|
|
|
|
|
|
grouping_label_list:
|
|
grouping_label_list COMMA grouping_label
|
|
{ $$ = append($1, $3.Val) }
|
|
| grouping_label
|
|
{ $$ = []string{$1.Val} }
|
|
| grouping_label_list error
|
|
{ yylex.(*parser).unexpected("grouping opts", "\",\" or \"}\"") }
|
|
;
|
|
|
|
grouping_label :
|
|
maybe_label
|
|
{
|
|
if !isLabel($1.Val) {
|
|
yylex.(*parser).unexpected("grouping opts", "label")
|
|
}
|
|
$$ = $1
|
|
}
|
|
| error
|
|
{ yylex.(*parser).unexpected("grouping opts", "label") }
|
|
;
|
|
|
|
|
|
/* inside of grouping options label names can be recognized as keywords by the lexer */
|
|
maybe_label :
|
|
IDENTIFIER
|
|
| METRIC_IDENTIFIER
|
|
| LAND
|
|
| LOR
|
|
| LUNLESS
|
|
| AVG
|
|
| COUNT
|
|
| SUM
|
|
| MIN
|
|
| MAX
|
|
| STDDEV
|
|
| STDVAR
|
|
| TOPK
|
|
| BOTTOMK
|
|
| COUNT_VALUES
|
|
| QUANTILE
|
|
| OFFSET
|
|
| BY
|
|
| ON
|
|
| IGNORING
|
|
| GROUP_LEFT
|
|
| GROUP_RIGHT
|
|
| BOOL
|
|
;
|
|
|
|
// The series description grammar is only used inside unit tests.
|
|
series_description:
|
|
metric series_values
|
|
{
|
|
yylex.(*parser).generatedParserResult = &seriesDescription{
|
|
labels: $1,
|
|
values: $2,
|
|
}
|
|
}
|
|
;
|
|
|
|
series_values :
|
|
/*empty*/
|
|
{ $$ = []sequenceValue{} }
|
|
| series_values SPACE series_item
|
|
{ $$ = append($1, $3...) }
|
|
| series_values SPACE
|
|
{ $$ = $1 }
|
|
| error
|
|
{ yylex.(*parser).unexpected("series values", "") }
|
|
;
|
|
|
|
series_item :
|
|
BLANK
|
|
{ $$ = []sequenceValue{{omitted: true}}}
|
|
| BLANK TIMES uint
|
|
{
|
|
$$ = []sequenceValue{}
|
|
for i:=uint64(0); i < $3; i++{
|
|
$$ = append($$, sequenceValue{omitted: true})
|
|
}
|
|
}
|
|
| series_value
|
|
{ $$ = []sequenceValue{{value: $1}}}
|
|
| series_value TIMES uint
|
|
{
|
|
$$ = []sequenceValue{}
|
|
for i:=uint64(0); i <= $3; i++{
|
|
$$ = append($$, sequenceValue{value: $1})
|
|
}
|
|
}
|
|
| series_value signed_number TIMES uint
|
|
{
|
|
$$ = []sequenceValue{}
|
|
for i:=uint64(0); i <= $4; i++{
|
|
$$ = append($$, sequenceValue{value: $1})
|
|
$1 += $2
|
|
}
|
|
}
|
|
uint :
|
|
NUMBER
|
|
{
|
|
var err error
|
|
$$, err = strconv.ParseUint($1.Val, 10, 64)
|
|
if err != nil {
|
|
yylex.(*parser).errorf("invalid repitition in series values: %s", err)
|
|
}
|
|
}
|
|
;
|
|
|
|
signed_number :
|
|
ADD number
|
|
{ $$ = $2 }
|
|
| SUB number
|
|
{ $$ = -$2 }
|
|
;
|
|
|
|
series_value :
|
|
IDENTIFIER
|
|
{
|
|
if $1.Val != "stale" {
|
|
yylex.(*parser).unexpected("series values", "number or \"stale\"")
|
|
}
|
|
$$ = math.Float64frombits(value.StaleNaN)
|
|
}
|
|
| number
|
|
{ $$ = $1 }
|
|
| signed_number
|
|
{ $$ = $1 }
|
|
;
|
|
|
|
|
|
|
|
number :
|
|
NUMBER
|
|
{$$ = yylex.(*parser).number($1.Val) }
|
|
;
|
|
|
|
%%
|