Skip to content

Commit

Permalink
adds stringer methods for all ast expr types (#1630)
Browse files Browse the repository at this point in the history
* adds stringer methods for all ast expr types

* Update pkg/logql/ast.go

Co-Authored-By: Cyril Tovena <cyril.tovena@gmail.com>

Co-authored-by: Cyril Tovena <cyril.tovena@gmail.com>
  • Loading branch information
owen-d and cyriltovena authored Feb 4, 2020
1 parent a135652 commit 6930fb2
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
66 changes: 65 additions & 1 deletion pkg/logql/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import (

"github.com/grafana/loki/pkg/iter"
"github.com/grafana/loki/pkg/logproto"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/promql"
)

// Expr is the root expression which can be a SampleExpr or LogSelectorExpr
type Expr interface {
logQLExpr() // ensure it's not implemented accidentally
fmt.Stringer
}

// SelectParams specifies parameters passed to data selections.
Expand Down Expand Up @@ -53,7 +55,6 @@ type Filter func(line []byte) bool
type LogSelectorExpr interface {
Filter() (Filter, error)
Matchers() []*labels.Matcher
fmt.Stringer
Expr
}

Expand Down Expand Up @@ -188,6 +189,16 @@ type logRange struct {
interval time.Duration
}

// impls Stringer
func (r logRange) String() string {
var sb strings.Builder
sb.WriteString("(")
sb.WriteString(r.left.String())
sb.WriteString(")")
sb.WriteString(fmt.Sprintf("[%v]", model.Duration(r.interval)))
return sb.String()
}

func newLogRange(left LogSelectorExpr, interval time.Duration) *logRange {
return &logRange{
left: left,
Expand Down Expand Up @@ -279,11 +290,34 @@ func (e *rangeAggregationExpr) Selector() LogSelectorExpr {
// impl Expr
func (e *rangeAggregationExpr) logQLExpr() {}

// impls Stringer
func (e *rangeAggregationExpr) String() string {
return formatOperation(e.operation, nil, e.left.String())
}

type grouping struct {
groups []string
without bool
}

// impls Stringer
func (g grouping) String() string {
var sb strings.Builder
if g.without {
sb.WriteString(" without")
} else if len(g.groups) > 0 {
sb.WriteString(" by")
}

if len(g.groups) > 0 {
sb.WriteString("(")
sb.WriteString(strings.Join(g.groups, ","))
sb.WriteString(")")
}

return sb.String()
}

type vectorAggregationExpr struct {
left SampleExpr

Expand Down Expand Up @@ -325,3 +359,33 @@ func (e *vectorAggregationExpr) Selector() LogSelectorExpr {

// impl Expr
func (e *vectorAggregationExpr) logQLExpr() {}

func (e *vectorAggregationExpr) String() string {
var params []string
if e.params != 0 {
params = []string{fmt.Sprintf("%d", e.params), e.left.String()}
} else {
params = []string{e.left.String()}
}
return formatOperation(e.operation, e.grouping, params...)
}

// helper used to impl Stringer for vector and range aggregations
func formatOperation(op string, grouping *grouping, params ...string) string {
nonEmptyParams := make([]string, 0, len(params))
for _, p := range params {
if p != "" {
nonEmptyParams = append(nonEmptyParams, p)
}
}

var sb strings.Builder
sb.WriteString(op)
if grouping != nil {
sb.WriteString(grouping.String())
}
sb.WriteString("(")
sb.WriteString(strings.Join(nonEmptyParams, ","))
sb.WriteString(")")
return sb.String()
}
22 changes: 22 additions & 0 deletions pkg/logql/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/prometheus/prometheus/pkg/labels"
)
Expand Down Expand Up @@ -33,6 +34,27 @@ func Test_logSelectorExpr_String(t *testing.T) {
}
}

func Test_SampleExpr_String(t *testing.T) {
t.Parallel()
for _, tc := range []string{
`rate( ( {job="mysql"} |="error" !="timeout" ) [10s] )`,
`sum without(a) ( rate ( ( {job="mysql"} |="error" !="timeout" ) [10s] ) )`,
`sum by(a) (rate( ( {job="mysql"} |="error" !="timeout" ) [10s] ) )`,
`sum(count_over_time({job="mysql"}[5m]))`,
`topk(10,sum(rate({region="us-east1"}[5m])) by (name))`,
`avg( rate( ( {job="nginx"} |= "GET" ) [10s] ) ) by (region)`,
} {
t.Run(tc, func(t *testing.T) {
expr, err := ParseExpr(tc)
require.Nil(t, err)

expr2, err := ParseExpr(expr.String())
require.Nil(t, err)
require.Equal(t, expr, expr2)
})
}
}

type linecheck struct {
l string
e bool
Expand Down

0 comments on commit 6930fb2

Please sign in to comment.