Skip to content

Commit 0bfb94d

Browse files
committed
feat(tsdb): add interval calculator
1 parent 4fafefd commit 0bfb94d

File tree

7 files changed

+244
-29
lines changed

7 files changed

+244
-29
lines changed

pkg/tsdb/influxdb/query_builder.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ func renderTags(query *Query) []string {
3030
}
3131

3232
func (*QueryBuilder) Build(query *Query, queryContext *tsdb.QueryContext) (string, error) {
33-
res := renderSelectors(query)
33+
res := renderSelectors(query, queryContext)
3434
res += renderMeasurement(query)
3535
res += renderWhereClause(query)
3636
res += renderTimeFilter(query, queryContext)
37-
res += renderGroupBy(query)
37+
res += renderGroupBy(query, queryContext)
3838

3939
return res, nil
4040
}
@@ -50,15 +50,15 @@ func renderTimeFilter(query *Query, queryContext *tsdb.QueryContext) string {
5050
return fmt.Sprintf("time > %s%s", from, to)
5151
}
5252

53-
func renderSelectors(query *Query) string {
53+
func renderSelectors(query *Query, queryContext *tsdb.QueryContext) string {
5454
res := "SELECT "
5555

5656
var selectors []string
5757
for _, sel := range query.Selects {
5858

5959
stk := ""
6060
for _, s := range *sel {
61-
stk = s.Render(stk)
61+
stk = s.Render(queryContext, stk)
6262
}
6363
selectors = append(selectors, stk)
6464
}
@@ -87,7 +87,7 @@ func renderWhereClause(query *Query) string {
8787
return res
8888
}
8989

90-
func renderGroupBy(query *Query) string {
90+
func renderGroupBy(query *Query, queryContext *tsdb.QueryContext) string {
9191
groupBy := ""
9292
for i, group := range query.GroupBy {
9393
if i == 0 {
@@ -100,7 +100,7 @@ func renderGroupBy(query *Query) string {
100100
groupBy += " "
101101
}
102102

103-
groupBy += group.Render("")
103+
groupBy += group.Render(queryContext, "")
104104
}
105105

106106
return groupBy

pkg/tsdb/influxdb/query_builder_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
3737

3838
rawQuery, err := builder.Build(query, queryContext)
3939
So(err, ShouldBeNil)
40-
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(10s) fill(null)`)
40+
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(200ms) fill(null)`)
4141
})
4242

4343
Convey("can build query with group bys", func() {
@@ -51,7 +51,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
5151

5252
rawQuery, err := builder.Build(query, queryContext)
5353
So(err, ShouldBeNil)
54-
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(10s), "datacenter" fill(null)`)
54+
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)`)
5555
})
5656

5757
Convey("can render time range", func() {

pkg/tsdb/influxdb/query_part.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package influxdb
33
import (
44
"fmt"
55
"strings"
6+
7+
"github.com/grafana/grafana/pkg/tsdb"
68
)
79

810
var renders map[string]QueryDefinition
@@ -13,7 +15,7 @@ type DefinitionParameters struct {
1315
}
1416

1517
type QueryDefinition struct {
16-
Renderer func(part *QueryPart, innerExpr string) string
18+
Renderer func(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string
1719
Params []DefinitionParameters
1820
}
1921

@@ -83,17 +85,17 @@ func init() {
8385
renders["alias"] = QueryDefinition{Renderer: aliasRenderer}
8486
}
8587

86-
func fieldRenderer(part *QueryPart, innerExpr string) string {
88+
func fieldRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
8789
if part.Params[0] == "*" {
8890
return "*"
8991
}
9092
return fmt.Sprintf(`"%s"`, part.Params[0])
9193
}
9294

93-
func functionRenderer(part *QueryPart, innerExpr string) string {
95+
func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
9496
for i, v := range part.Params {
9597
if v == "$interval" {
96-
part.Params[i] = "10s"
98+
part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange)
9799
}
98100
}
99101

@@ -106,16 +108,16 @@ func functionRenderer(part *QueryPart, innerExpr string) string {
106108
return fmt.Sprintf("%s(%s)", part.Type, params)
107109
}
108110

109-
func suffixRenderer(part *QueryPart, innerExpr string) string {
111+
func suffixRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
110112
return fmt.Sprintf("%s %s", innerExpr, part.Params[0])
111113
}
112114

113-
func aliasRenderer(part *QueryPart, innerExpr string) string {
115+
func aliasRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
114116
return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0])
115117
}
116118

117-
func (r QueryDefinition) Render(part *QueryPart, innerExpr string) string {
118-
return r.Renderer(part, innerExpr)
119+
func (r QueryDefinition) Render(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
120+
return r.Renderer(queryContext, part, innerExpr)
119121
}
120122

121123
func NewQueryPart(typ string, params []string) (*QueryPart, error) {
@@ -138,6 +140,6 @@ type QueryPart struct {
138140
Params []string
139141
}
140142

141-
func (qp *QueryPart) Render(expr string) string {
142-
return qp.Def.Renderer(qp, expr)
143+
func (qp *QueryPart) Render(queryContext *tsdb.QueryContext, expr string) string {
144+
return qp.Def.Renderer(queryContext, qp, expr)
143145
}

pkg/tsdb/influxdb/query_part_test.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,70 @@ package influxdb
33
import (
44
"testing"
55

6+
"github.com/grafana/grafana/pkg/tsdb"
67
. "github.com/smartystreets/goconvey/convey"
78
)
89

910
func TestInfluxdbQueryPart(t *testing.T) {
1011
Convey("Influxdb query parts", t, func() {
1112

13+
queryContext := &tsdb.QueryContext{
14+
TimeRange: tsdb.NewTimeRange("5m", "now"),
15+
}
16+
1217
Convey("render field ", func() {
1318
part, err := NewQueryPart("field", []string{"value"})
1419
So(err, ShouldBeNil)
1520

16-
res := part.Render("value")
21+
res := part.Render(queryContext, "value")
1722
So(res, ShouldEqual, `"value"`)
1823
})
1924

2025
Convey("render nested part", func() {
2126
part, err := NewQueryPart("derivative", []string{"10s"})
2227
So(err, ShouldBeNil)
2328

24-
res := part.Render("mean(value)")
29+
res := part.Render(queryContext, "mean(value)")
2530
So(res, ShouldEqual, "derivative(mean(value), 10s)")
2631
})
2732

2833
Convey("render bottom", func() {
2934
part, err := NewQueryPart("bottom", []string{"3"})
3035
So(err, ShouldBeNil)
3136

32-
res := part.Render("value")
37+
res := part.Render(queryContext, "value")
3338
So(res, ShouldEqual, "bottom(value, 3)")
3439
})
3540

3641
Convey("render time", func() {
3742
part, err := NewQueryPart("time", []string{"$interval"})
3843
So(err, ShouldBeNil)
3944

40-
res := part.Render("")
41-
So(res, ShouldEqual, "time(10s)")
45+
res := part.Render(queryContext, "")
46+
So(res, ShouldEqual, "time(200ms)")
4247
})
4348

4449
Convey("render spread", func() {
4550
part, err := NewQueryPart("spread", []string{})
4651
So(err, ShouldBeNil)
4752

48-
res := part.Render("value")
53+
res := part.Render(queryContext, "value")
4954
So(res, ShouldEqual, `spread(value)`)
5055
})
5156

5257
Convey("render suffix", func() {
5358
part, err := NewQueryPart("math", []string{"/ 100"})
5459
So(err, ShouldBeNil)
5560

56-
res := part.Render("mean(value)")
61+
res := part.Render(queryContext, "mean(value)")
5762
So(res, ShouldEqual, "mean(value) / 100")
5863
})
5964

6065
Convey("render alias", func() {
6166
part, err := NewQueryPart("alias", []string{"test"})
6267
So(err, ShouldBeNil)
6368

64-
res := part.Render("mean(value)")
69+
res := part.Render(queryContext, "mean(value)")
6570
So(res, ShouldEqual, `mean(value) AS "test"`)
6671
})
6772
})

pkg/tsdb/influxdb/response_parser.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ func (rp *ResponseParser) Parse(response *Response) *tsdb.QueryResult {
1818
rp.parseResult(result.Series, queryRes)
1919
}
2020

21-
for _, serie := range queryRes.Series {
22-
glog.Debug("result", "name", serie.Name, "points", serie.Points)
23-
}
21+
/*
22+
for _, serie := range queryRes.Series {
23+
glog.Debug("result", "name", serie.Name, "points", serie.Points)
24+
}
25+
*/
2426

2527
return queryRes
2628
}

pkg/tsdb/interval.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package tsdb
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/grafana/grafana/pkg/log"
8+
)
9+
10+
var (
11+
defaultRes int64 = 1500
12+
minInterval time.Duration = 1 * time.Millisecond
13+
year time.Duration = time.Hour * 24 * 365
14+
day time.Duration = time.Hour * 24 * 365
15+
)
16+
17+
func CalculateInterval(timerange *TimeRange) string {
18+
interval := time.Duration((timerange.MustGetTo().UnixNano() - timerange.MustGetFrom().UnixNano()) / defaultRes)
19+
20+
log.Info2("res", "resinMs", time.Duration(interval).String())
21+
22+
if interval < minInterval {
23+
return formatDuration(minInterval)
24+
}
25+
26+
return formatDuration(roundInterval(interval))
27+
}
28+
29+
func formatDuration(inter time.Duration) string {
30+
if inter >= year {
31+
return fmt.Sprintf("%dy", inter/year)
32+
}
33+
34+
if inter >= day {
35+
return fmt.Sprintf("%dd", inter/day)
36+
}
37+
38+
if inter >= time.Hour {
39+
return fmt.Sprintf("%dh", inter/time.Hour)
40+
}
41+
42+
if inter >= time.Minute {
43+
return fmt.Sprintf("%dm", inter/time.Minute)
44+
}
45+
46+
if inter >= time.Second {
47+
return fmt.Sprintf("%ds", inter/time.Second)
48+
}
49+
50+
if inter >= time.Millisecond {
51+
return fmt.Sprintf("%dms", inter/time.Millisecond)
52+
}
53+
54+
return "1ms"
55+
}
56+
57+
func roundInterval(interval time.Duration) time.Duration {
58+
switch true {
59+
// 0.015s
60+
case interval <= 15*time.Millisecond:
61+
return time.Millisecond * 10 // 0.01s
62+
// 0.035s
63+
case interval <= 35*time.Millisecond:
64+
return time.Millisecond * 20 // 0.02s
65+
// 0.075s
66+
case interval <= 75*time.Millisecond:
67+
return time.Millisecond * 50 // 0.05s
68+
// 0.15s
69+
case interval <= 150*time.Millisecond:
70+
return time.Millisecond * 100 // 0.1s
71+
// 0.35s
72+
case interval <= 350*time.Millisecond:
73+
return time.Millisecond * 200 // 0.2s
74+
// 0.75s
75+
case interval <= 750*time.Millisecond:
76+
return time.Millisecond * 500 // 0.5s
77+
// 1.5s
78+
case interval <= 1500*time.Millisecond:
79+
return time.Millisecond * 1000 // 1s
80+
// 3.5s
81+
case interval <= 3500*time.Millisecond:
82+
return time.Millisecond * 2000 // 2s
83+
// 7.5s
84+
case interval <= 7500*time.Millisecond:
85+
return time.Millisecond * 5000 // 5s
86+
// 12.5s
87+
case interval <= 12500*time.Millisecond:
88+
return time.Millisecond * 10000 // 10s
89+
// 17.5s
90+
case interval <= 17500*time.Millisecond:
91+
return time.Millisecond * 15000 // 15s
92+
// 25s
93+
case interval <= 25000*time.Millisecond:
94+
return time.Millisecond * 20000 // 20s
95+
// 45s
96+
case interval <= 45000*time.Millisecond:
97+
return time.Millisecond * 30000 // 30s
98+
// 1.5m
99+
case interval <= 90000*time.Millisecond:
100+
return time.Millisecond * 60000 // 1m
101+
// 3.5m
102+
case interval <= 210000*time.Millisecond:
103+
return time.Millisecond * 120000 // 2m
104+
// 7.5m
105+
case interval <= 450000*time.Millisecond:
106+
return time.Millisecond * 300000 // 5m
107+
// 12.5m
108+
case interval <= 750000*time.Millisecond:
109+
return time.Millisecond * 600000 // 10m
110+
// 12.5m
111+
case interval <= 1050000*time.Millisecond:
112+
return time.Millisecond * 900000 // 15m
113+
// 25m
114+
case interval <= 1500000*time.Millisecond:
115+
return time.Millisecond * 1200000 // 20m
116+
// 45m
117+
case interval <= 2700000*time.Millisecond:
118+
return time.Millisecond * 1800000 // 30m
119+
// 1.5h
120+
case interval <= 5400000*time.Millisecond:
121+
return time.Millisecond * 3600000 // 1h
122+
// 2.5h
123+
case interval <= 9000000*time.Millisecond:
124+
return time.Millisecond * 7200000 // 2h
125+
// 4.5h
126+
case interval <= 16200000*time.Millisecond:
127+
return time.Millisecond * 10800000 // 3h
128+
// 9h
129+
case interval <= 32400000*time.Millisecond:
130+
return time.Millisecond * 21600000 // 6h
131+
// 24h
132+
case interval <= 86400000*time.Millisecond:
133+
return time.Millisecond * 43200000 // 12h
134+
// 48h
135+
case interval <= 172800000*time.Millisecond:
136+
return time.Millisecond * 86400000 // 24h
137+
// 1w
138+
case interval <= 604800000*time.Millisecond:
139+
return time.Millisecond * 86400000 // 24h
140+
// 3w
141+
case interval <= 1814400000*time.Millisecond:
142+
return time.Millisecond * 604800000 // 1w
143+
// 2y
144+
case interval < 3628800000*time.Millisecond:
145+
return time.Millisecond * 2592000000 // 30d
146+
default:
147+
return time.Millisecond * 31536000000 // 1y
148+
}
149+
}

0 commit comments

Comments
 (0)