Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TraceQL] quantile_over_time 1 of 2 - lang/parser #3605

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions pkg/traceql/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -753,10 +753,16 @@ var (
_ pipelineElement = (*GroupOperation)(nil)
)

// MetricsAggregate is a placeholder in the AST for a metrics aggregation
// pipeline element. It has a superset of the properties of them all, and
// builds them later via init() so that appropriate buffers can be allocated
// for the query time range and step.
type MetricsAggregate struct {
op MetricsAggregateOp
by []Attribute
agg SpanAggregator
op MetricsAggregateOp
by []Attribute
attr Attribute
floats []float64
agg SpanAggregator
}

func newMetricsAggregate(agg MetricsAggregateOp, by []Attribute) *MetricsAggregate {
Expand All @@ -766,6 +772,15 @@ func newMetricsAggregate(agg MetricsAggregateOp, by []Attribute) *MetricsAggrega
}
}

func newMetricsAggregateQuantileOverTime(attr Attribute, qs []float64, by []Attribute) *MetricsAggregate {
return &MetricsAggregate{
op: metricsAggregateQuantileOverTime,
floats: qs,
attr: attr,
by: by,
}
}

func (a *MetricsAggregate) extractConditions(request *FetchSpansRequest) {
switch a.op {
case metricsAggregateRate, metricsAggregateCountOverTime:
Expand Down
49 changes: 47 additions & 2 deletions pkg/traceql/ast_stringer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ import (
)

func (r RootExpr) String() string {
return r.Pipeline.String()
s := strings.Builder{}
s.WriteString(r.Pipeline.String())
if r.MetricsPipeline != nil {
s.WriteString(" | ")
s.WriteString(r.MetricsPipeline.String())
}
if r.Hints != nil {
s.WriteString(" ")
s.WriteString(r.Hints.String())
}
return s.String()
}

func (p Pipeline) String() string {
Expand Down Expand Up @@ -126,7 +136,42 @@ func (a Attribute) String() string {
}

func (a MetricsAggregate) String() string {
return a.op.String()
s := strings.Builder{}

s.WriteString(a.op.String())
s.WriteString("(")
switch a.op {
case metricsAggregateQuantileOverTime:
s.WriteString(a.attr.String())
s.WriteString(",")
for i, f := range a.floats {
s.WriteString(strconv.FormatFloat(f, 'f', 5, 64))
if i < len(a.floats)-1 {
s.WriteString(",")
}
}
}
s.WriteString(")")

if len(a.by) > 0 {
s.WriteString("by(")
for i, b := range a.by {
s.WriteString(b.String())
if i < len(a.by)-1 {
s.WriteString(",")
}
}
s.WriteString(")")
}
return s.String()
}

func (h *Hints) String() string {
hh := make([]string, 0, len(h.Hints))
for _, hn := range h.Hints {
hh = append(hh, hn.Name+"="+hn.Value.String())
}
return "with(" + strings.Join(hh, ",") + ")"
}

func binaryOp(op Operator, lhs Element, rhs Element) string {
Expand Down
36 changes: 22 additions & 14 deletions pkg/traceql/ast_stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,30 @@ func TestStringer(t *testing.T) {
err = yaml.Unmarshal(b, queries)
require.NoError(t, err)

for _, q := range queries.Valid {
t.Run(q, func(t *testing.T) {
pass1, err := Parse(q)
require.NoError(t, err)
// All of these queries are parseable and valid constructs, and should be roundtrippable.
sets := [][]string{
queries.Valid,
queries.Unsupported,
}

// now parse it a second time and confirm that it parses the same way twice
pass2, err := Parse(pass1.String())
ok := assert.NoError(t, err)
if !ok {
t.Logf("\n\t1: %s", pass1.String())
return
}
for _, s := range sets {
for _, q := range s {
t.Run(q, func(t *testing.T) {
pass1, err := Parse(q)
require.NoError(t, err)

assert.Equal(t, pass1, pass2)
t.Logf("\n\tq: %s\n\t1: %s\n\t2: %s", q, pass1.String(), pass2.String())
})
// now parse it a second time and confirm that it parses the same way twice
pass2, err := Parse(pass1.String())
ok := assert.NoError(t, err)
if !ok {
t.Logf("\n\t1: %s", pass1.String())
return
}

assert.Equal(t, pass1, pass2)
t.Logf("\n\tq: %s\n\t1: %s\n\t2: %s", q, pass1.String(), pass2.String())
})
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/traceql/ast_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,7 @@ func (a Attribute) validate() error {

return nil
}

func (h *Hints) validate() error {
return nil
}
3 changes: 3 additions & 0 deletions pkg/traceql/enum_aggregates.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type MetricsAggregateOp int
const (
metricsAggregateRate MetricsAggregateOp = iota
metricsAggregateCountOverTime
metricsAggregateQuantileOverTime
)

func (a MetricsAggregateOp) String() string {
Expand All @@ -42,6 +43,8 @@ func (a MetricsAggregateOp) String() string {
return "rate"
case metricsAggregateCountOverTime:
return "count_over_time"
case metricsAggregateQuantileOverTime:
return "quantile_over_time"
}

return fmt.Sprintf("aggregate(%d)", a)
Expand Down
2 changes: 2 additions & 0 deletions pkg/traceql/enum_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@ func (h *Hints) Get(k string, t StaticType, allowUnsafe bool) (v Static, ok bool

return
}

var _ Element = (*Hints)(nil)
30 changes: 24 additions & 6 deletions pkg/traceql/expr.y
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ import (
static Static
intrinsicField Attribute
attributeField Attribute
attribute Attribute

binOp Operator
staticInt int
staticStr string
staticFloat float64
staticDuration time.Duration
numericList []float64

hint *Hint
hintList []*Hint
Expand Down Expand Up @@ -73,6 +75,9 @@ import (
%type <static> static
%type <intrinsicField> intrinsicField
%type <attributeField> attributeField
%type <attribute> attribute

%type <numericList> numericList

%type <hint> hint
%type <hintList> hintList
Expand All @@ -90,7 +95,7 @@ import (
COUNT AVG MAX MIN SUM
BY COALESCE SELECT
END_ATTRIBUTE
RATE COUNT_OVER_TIME
RATE COUNT_OVER_TIME QUANTILE_OVER_TIME
WITH

// Operators are listed with increasing precedence.
Expand Down Expand Up @@ -161,11 +166,22 @@ selectOperation:
SELECT OPEN_PARENS attributeList CLOSE_PARENS { $$ = newSelectOperation($3) }
;

attribute:
intrinsicField { $$ = $1 }
| attributeField { $$ = $1 }
;

attributeList:
intrinsicField { $$ = []Attribute{$1} }
| attributeField { $$ = []Attribute{$1} }
| attributeList COMMA intrinsicField { $$ = append($1, $3) }
| attributeList COMMA attributeField { $$ = append($1, $3) }
attribute { $$ = []Attribute{$1} }
| attributeList COMMA attribute { $$ = append($1, $3) }
;

// Comma-separated list of numeric values. Casts all to floats
numericList:
FLOAT { $$ = []float64{$1} }
| INTEGER { $$ = []float64{float64($1)}}
| numericList COMMA FLOAT { $$ = append($1, $3) }
| numericList COMMA INTEGER { $$ = append($1, float64($3))}
;

spansetExpression: // shares the same operators as scalarPipelineExpression. split out for readability
Expand Down Expand Up @@ -262,9 +278,11 @@ aggregate:
// **********************
metricsAggregation:
RATE OPEN_PARENS CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateRate, nil) }
| COUNT_OVER_TIME OPEN_PARENS CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateCountOverTime, nil) }
| RATE OPEN_PARENS CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateRate, $6) }
| COUNT_OVER_TIME OPEN_PARENS CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateCountOverTime, nil) }
| COUNT_OVER_TIME OPEN_PARENS CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregate(metricsAggregateCountOverTime, $6) }
| QUANTILE_OVER_TIME OPEN_PARENS attribute COMMA numericList CLOSE_PARENS { $$ = newMetricsAggregateQuantileOverTime($3, $5, nil) }
| QUANTILE_OVER_TIME OPEN_PARENS attribute COMMA numericList CLOSE_PARENS BY OPEN_PARENS attributeList CLOSE_PARENS { $$ = newMetricsAggregateQuantileOverTime($3, $5, $9) }
;

// **********************
Expand Down
Loading
Loading