mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(influxdb): start parsing interval parameters
This commit is contained in:
parent
1506df8c11
commit
4144eacc24
@ -91,7 +91,8 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice,
|
|||||||
|
|
||||||
func (e *InfluxDBExecutor) getQuery(queries tsdb.QuerySlice, context *tsdb.QueryContext) (string, error) {
|
func (e *InfluxDBExecutor) getQuery(queries tsdb.QuerySlice, context *tsdb.QueryContext) (string, error) {
|
||||||
for _, v := range queries {
|
for _, v := range queries {
|
||||||
query, err := e.QueryParser.Parse(v.Model)
|
|
||||||
|
query, err := e.QueryParser.Parse(v.Model, e.DataSourceInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,15 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InfluxdbQueryParser struct{}
|
type InfluxdbQueryParser struct{}
|
||||||
|
|
||||||
func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) {
|
func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *tsdb.DataSourceInfo) (*Query, error) {
|
||||||
policy := model.Get("policy").MustString("default")
|
policy := model.Get("policy").MustString("default")
|
||||||
rawQuery := model.Get("query").MustString("")
|
rawQuery := model.Get("query").MustString("")
|
||||||
|
interval := model.Get("interval").MustString("")
|
||||||
|
|
||||||
measurement := model.Get("measurement").MustString("")
|
measurement := model.Get("measurement").MustString("")
|
||||||
|
|
||||||
@ -34,6 +36,13 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if interval == "" {
|
||||||
|
dsInterval := dsInfo.JsonData.Get("timeInterval").MustString("")
|
||||||
|
if dsInterval != "" {
|
||||||
|
interval = dsInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &Query{
|
return &Query{
|
||||||
Measurement: measurement,
|
Measurement: measurement,
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
@ -42,6 +51,7 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) {
|
|||||||
Tags: tags,
|
Tags: tags,
|
||||||
Selects: selects,
|
Selects: selects,
|
||||||
RawQuery: rawQuery,
|
RawQuery: rawQuery,
|
||||||
|
Interval: interval,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,6 +12,9 @@ func TestInfluxdbQueryParser(t *testing.T) {
|
|||||||
Convey("Influxdb query parser", t, func() {
|
Convey("Influxdb query parser", t, func() {
|
||||||
|
|
||||||
parser := &InfluxdbQueryParser{}
|
parser := &InfluxdbQueryParser{}
|
||||||
|
dsInfo := &tsdb.DataSourceInfo{
|
||||||
|
JsonData: simplejson.New(),
|
||||||
|
}
|
||||||
|
|
||||||
Convey("can parse influxdb json model", func() {
|
Convey("can parse influxdb json model", func() {
|
||||||
json := `
|
json := `
|
||||||
@ -101,15 +105,16 @@ func TestInfluxdbQueryParser(t *testing.T) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
dsInfo.JsonData.Set("timeInterval", ">20s")
|
||||||
modelJson, err := simplejson.NewJson([]byte(json))
|
modelJson, err := simplejson.NewJson([]byte(json))
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res, err := parser.Parse(modelJson)
|
res, err := parser.Parse(modelJson, dsInfo)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(res.GroupBy), ShouldEqual, 3)
|
So(len(res.GroupBy), ShouldEqual, 3)
|
||||||
So(len(res.Selects), ShouldEqual, 3)
|
So(len(res.Selects), ShouldEqual, 3)
|
||||||
So(len(res.Tags), ShouldEqual, 2)
|
So(len(res.Tags), ShouldEqual, 2)
|
||||||
|
So(res.Interval, ShouldEqual, ">20s")
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("can part raw query json model", func() {
|
Convey("can part raw query json model", func() {
|
||||||
@ -130,6 +135,7 @@ func TestInfluxdbQueryParser(t *testing.T) {
|
|||||||
"type": "fill"
|
"type": "fill"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"interval": ">10s",
|
||||||
"policy": "default",
|
"policy": "default",
|
||||||
"query": "RawDummieQuery",
|
"query": "RawDummieQuery",
|
||||||
"rawQuery": true,
|
"rawQuery": true,
|
||||||
@ -160,12 +166,13 @@ func TestInfluxdbQueryParser(t *testing.T) {
|
|||||||
modelJson, err := simplejson.NewJson([]byte(json))
|
modelJson, err := simplejson.NewJson([]byte(json))
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res, err := parser.Parse(modelJson)
|
res, err := parser.Parse(modelJson, dsInfo)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(res.RawQuery, ShouldEqual, "RawDummieQuery")
|
So(res.RawQuery, ShouldEqual, "RawDummieQuery")
|
||||||
So(len(res.GroupBy), ShouldEqual, 2)
|
So(len(res.GroupBy), ShouldEqual, 2)
|
||||||
So(len(res.Selects), ShouldEqual, 1)
|
So(len(res.Selects), ShouldEqual, 1)
|
||||||
So(len(res.Tags), ShouldEqual, 0)
|
So(len(res.Tags), ShouldEqual, 0)
|
||||||
|
So(res.Interval, ShouldEqual, ">10s")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func (qb *QueryBuilder) renderSelectors(query *Query, queryContext *tsdb.QueryCo
|
|||||||
|
|
||||||
stk := ""
|
stk := ""
|
||||||
for _, s := range *sel {
|
for _, s := range *sel {
|
||||||
stk = s.Render(queryContext, stk)
|
stk = s.Render(query, queryContext, stk)
|
||||||
}
|
}
|
||||||
selectors = append(selectors, stk)
|
selectors = append(selectors, stk)
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ func (qb *QueryBuilder) renderGroupBy(query *Query, queryContext *tsdb.QueryCont
|
|||||||
groupBy += " "
|
groupBy += " "
|
||||||
}
|
}
|
||||||
|
|
||||||
groupBy += group.Render(queryContext, "")
|
groupBy += group.Render(query, queryContext, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupBy
|
return groupBy
|
||||||
|
@ -37,7 +37,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
|
|||||||
|
|
||||||
rawQuery, err := builder.Build(query, queryContext)
|
rawQuery, err := builder.Build(query, queryContext)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(200ms) fill(null)`)
|
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(10s) fill(null)`)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("can build query with group bys", func() {
|
Convey("can build query with group bys", func() {
|
||||||
@ -51,7 +51,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
|
|||||||
|
|
||||||
rawQuery, err := builder.Build(query, queryContext)
|
rawQuery, err := builder.Build(query, queryContext)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(200ms), "datacenter" fill(null)`)
|
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(5s), "datacenter" fill(null)`)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("can render time range", func() {
|
Convey("can render time range", func() {
|
||||||
|
@ -15,7 +15,7 @@ type DefinitionParameters struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryDefinition struct {
|
type QueryDefinition struct {
|
||||||
Renderer func(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string
|
Renderer func(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string
|
||||||
Params []DefinitionParameters
|
Params []DefinitionParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,17 +85,22 @@ func init() {
|
|||||||
renders["alias"] = QueryDefinition{Renderer: aliasRenderer}
|
renders["alias"] = QueryDefinition{Renderer: aliasRenderer}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fieldRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
func fieldRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
||||||
if part.Params[0] == "*" {
|
if part.Params[0] == "*" {
|
||||||
return "*"
|
return "*"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`"%s"`, part.Params[0])
|
return fmt.Sprintf(`"%s"`, part.Params[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
func functionRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
||||||
for i, v := range part.Params {
|
for i, v := range part.Params {
|
||||||
if v == "$interval" {
|
if v == "$interval" {
|
||||||
part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange)
|
if query.Interval != "" {
|
||||||
|
interval := strings.Replace(strings.Replace(query.Interval, "<", "", 1), ">", "", 1)
|
||||||
|
part.Params[i] = interval
|
||||||
|
} else {
|
||||||
|
part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,16 +113,16 @@ func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExp
|
|||||||
return fmt.Sprintf("%s(%s)", part.Type, params)
|
return fmt.Sprintf("%s(%s)", part.Type, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func suffixRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
func suffixRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
||||||
return fmt.Sprintf("%s %s", innerExpr, part.Params[0])
|
return fmt.Sprintf("%s %s", innerExpr, part.Params[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func aliasRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
func aliasRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
||||||
return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0])
|
return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r QueryDefinition) Render(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
func (r QueryDefinition) Render(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
|
||||||
return r.Renderer(queryContext, part, innerExpr)
|
return r.Renderer(query, queryContext, part, innerExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQueryPart(typ string, params []string) (*QueryPart, error) {
|
func NewQueryPart(typ string, params []string) (*QueryPart, error) {
|
||||||
@ -140,6 +145,6 @@ type QueryPart struct {
|
|||||||
Params []string
|
Params []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qp *QueryPart) Render(queryContext *tsdb.QueryContext, expr string) string {
|
func (qp *QueryPart) Render(query *Query, queryContext *tsdb.QueryContext, expr string) string {
|
||||||
return qp.Def.Renderer(queryContext, qp, expr)
|
return qp.Def.Renderer(query, queryContext, qp, expr)
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,14 @@ import (
|
|||||||
func TestInfluxdbQueryPart(t *testing.T) {
|
func TestInfluxdbQueryPart(t *testing.T) {
|
||||||
Convey("Influxdb query parts", t, func() {
|
Convey("Influxdb query parts", t, func() {
|
||||||
|
|
||||||
queryContext := &tsdb.QueryContext{
|
queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("5m", "now")}
|
||||||
TimeRange: tsdb.NewTimeRange("5m", "now"),
|
query := &Query{}
|
||||||
}
|
|
||||||
|
|
||||||
Convey("render field ", func() {
|
Convey("render field ", func() {
|
||||||
part, err := NewQueryPart("field", []string{"value"})
|
part, err := NewQueryPart("field", []string{"value"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "value")
|
res := part.Render(query, queryContext, "value")
|
||||||
So(res, ShouldEqual, `"value"`)
|
So(res, ShouldEqual, `"value"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("derivative", []string{"10s"})
|
part, err := NewQueryPart("derivative", []string{"10s"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "mean(value)")
|
res := part.Render(query, queryContext, "mean(value)")
|
||||||
So(res, ShouldEqual, "derivative(mean(value), 10s)")
|
So(res, ShouldEqual, "derivative(mean(value), 10s)")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("bottom", []string{"3"})
|
part, err := NewQueryPart("bottom", []string{"3"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "value")
|
res := part.Render(query, queryContext, "value")
|
||||||
So(res, ShouldEqual, "bottom(value, 3)")
|
So(res, ShouldEqual, "bottom(value, 3)")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("time", []string{"$interval"})
|
part, err := NewQueryPart("time", []string{"$interval"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "")
|
res := part.Render(query, queryContext, "")
|
||||||
So(res, ShouldEqual, "time(200ms)")
|
So(res, ShouldEqual, "time(200ms)")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("spread", []string{})
|
part, err := NewQueryPart("spread", []string{})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "value")
|
res := part.Render(query, queryContext, "value")
|
||||||
So(res, ShouldEqual, `spread(value)`)
|
So(res, ShouldEqual, `spread(value)`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("math", []string{"/ 100"})
|
part, err := NewQueryPart("math", []string{"/ 100"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "mean(value)")
|
res := part.Render(query, queryContext, "mean(value)")
|
||||||
So(res, ShouldEqual, "mean(value) / 100")
|
So(res, ShouldEqual, "mean(value) / 100")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -66,7 +65,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
|
|||||||
part, err := NewQueryPart("alias", []string{"test"})
|
part, err := NewQueryPart("alias", []string{"test"})
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
res := part.Render(queryContext, "mean(value)")
|
res := part.Render(query, queryContext, "mean(value)")
|
||||||
So(res, ShouldEqual, `mean(value) AS "test"`)
|
So(res, ShouldEqual, `mean(value) AS "test"`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user