Skip to content

Commit

Permalink
Merge pull request #9153 from influxdata/er-prom-parsing
Browse files Browse the repository at this point in the history
Fix Prometheus regex parsing
  • Loading branch information
e-dard authored Jan 2, 2018
2 parents bf283f0 + 8e3d29e commit 1f3352e
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 2 deletions.
17 changes: 16 additions & 1 deletion prometheus/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math"
"regexp"
"time"

"github.com/influxdata/influxdb/models"
Expand Down Expand Up @@ -93,6 +94,8 @@ func ReadRequestToInfluxQLQuery(req *remote.ReadRequest, db, rp string) (*influx
// condFromMatcher converts a Prometheus LabelMatcher into an equivalent InfluxQL BinaryExpr
func condFromMatcher(m *remote.LabelMatcher) (*influxql.BinaryExpr, error) {
var op influxql.Token
var rhs influxql.Expr

switch m.Type {
case remote.MatchType_EQUAL:
op = influxql.EQ
Expand All @@ -106,10 +109,22 @@ func condFromMatcher(m *remote.LabelMatcher) (*influxql.BinaryExpr, error) {
return nil, fmt.Errorf("unknown match type %v", m.Type)
}

if op == influxql.EQREGEX || op == influxql.NEQREGEX {
re, err := regexp.Compile(m.Value)
if err != nil {
return nil, err
}

// Convert regex values to InfluxDB format.
rhs = &influxql.RegexLiteral{Val: re}
} else {
rhs = &influxql.StringLiteral{Val: m.Value}
}

return &influxql.BinaryExpr{
Op: op,
LHS: &influxql.VarRef{Val: m.Name},
RHS: &influxql.StringLiteral{Val: m.Value},
RHS: rhs,
}, nil
}

Expand Down
97 changes: 97 additions & 0 deletions prometheus/converters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package prometheus_test

import (
"errors"
"reflect"
"testing"

"github.com/influxdata/influxdb/prometheus"
"github.com/influxdata/influxdb/prometheus/remote"
"github.com/influxdata/influxql"
)

func TestReadRequestToInfluxQLQuery(t *testing.T) {
examples := []struct {
name string
queries []*remote.Query
expQuery string
expError error
}{
{
name: "too many queries",
queries: []*remote.Query{{}, {}}, // Multiple queries
expError: errors.New("Prometheus read endpoint currently only supports one query at a time"),
},
{
name: "single condition",
queries: []*remote.Query{{
StartTimestampMs: 1,
EndTimestampMs: 100,
Matchers: []*remote.LabelMatcher{
{Name: "region", Value: "west", Type: remote.MatchType_EQUAL},
},
}},
expQuery: "SELECT f64 FROM db0.rp0._ WHERE region = 'west' AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.1Z' GROUP BY *",
},
{
name: "multiple conditions",
queries: []*remote.Query{{
StartTimestampMs: 1,
EndTimestampMs: 100,
Matchers: []*remote.LabelMatcher{
{Name: "region", Value: "west", Type: remote.MatchType_EQUAL},
{Name: "host", Value: "serverA", Type: remote.MatchType_NOT_EQUAL},
},
}},
expQuery: "SELECT f64 FROM db0.rp0._ WHERE region = 'west' AND host != 'serverA' AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.1Z' GROUP BY *",
},
{
name: "rewrite regex",
queries: []*remote.Query{{
StartTimestampMs: 1,
EndTimestampMs: 100,
Matchers: []*remote.LabelMatcher{
{Name: "region", Value: "c.*", Type: remote.MatchType_REGEX_MATCH},
{Name: "host", Value: `\d`, Type: remote.MatchType_REGEX_NO_MATCH},
},
}},
expQuery: `SELECT f64 FROM db0.rp0._ WHERE region =~ /c.*/ AND host !~ /\d/ AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.1Z' GROUP BY *`,
},
{
name: "escape regex",
queries: []*remote.Query{{
StartTimestampMs: 1,
EndTimestampMs: 100,
Matchers: []*remote.LabelMatcher{
{Name: "test_type", Value: "a/b", Type: remote.MatchType_REGEX_MATCH},
},
}},
expQuery: `SELECT f64 FROM db0.rp0._ WHERE test_type =~ /a\/b/ AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.1Z' GROUP BY *`,
},
}

for _, example := range examples {
t.Run(example.name, func(t *testing.T) {
readRequest := &remote.ReadRequest{Queries: example.queries}
query, err := prometheus.ReadRequestToInfluxQLQuery(readRequest, "db0", "rp0")
if !reflect.DeepEqual(err, example.expError) {
t.Errorf("got error %v, expected %v", err, example.expError)
}

var queryString string
if query != nil {
queryString = query.String()
}

if queryString != example.expQuery {
t.Errorf("got query %v, expected %v", queryString, example.expQuery)
}

if queryString != "" {
if _, err := influxql.ParseStatement(queryString); err != nil {
t.Error(err)
}
}
})
}
}
2 changes: 1 addition & 1 deletion services/httpd/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ func TestHandler_PromRead(t *testing.T) {

h := NewHandler(false)
h.StatementExecutor.ExecuteStatementFn = func(stmt influxql.Statement, ctx query.ExecutionContext) error {
if stmt.String() != `SELECT f64 FROM foo.._ WHERE eq = 'a' AND neq != 'b' AND regex =~ 'c' AND neqregex !~ 'd' AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.002Z' GROUP BY *` {
if stmt.String() != `SELECT f64 FROM foo.._ WHERE eq = 'a' AND neq != 'b' AND regex =~ /c/ AND neqregex !~ /d/ AND time >= '1970-01-01T00:00:00.001Z' AND time <= '1970-01-01T00:00:00.002Z' GROUP BY *` {
t.Fatalf("unexpected query: %s", stmt.String())
} else if ctx.Database != `foo` {
t.Fatalf("unexpected db: %s", ctx.Database)
Expand Down

0 comments on commit 1f3352e

Please sign in to comment.