Ensure backwards compat for old GROUP BY :interval:

pull/2890/head
Michael Desa 2018-02-28 17:21:15 -05:00
parent 3609bc7d3a
commit 1c9ee296a0
3 changed files with 37 additions and 147 deletions

View File

@ -1,6 +1,7 @@
package influx
import (
"regexp"
"sort"
"strconv"
"strings"
@ -37,6 +38,8 @@ func SortTemplates(ts []chronograf.TemplateVar) []chronograf.TemplateVar {
return ts
}
var groupByRe = regexp.MustCompile("(?i)GROUP BY :interval:")
// RenderTemplate converts the template variable into a correct InfluxQL string based
// on its type
func RenderTemplate(query string, t chronograf.TemplateVar, now time.Time) (string, error) {
@ -63,6 +66,8 @@ func RenderTemplate(query string, t chronograf.TemplateVar, now time.Time) (stri
tv[t.Values[i].Type] = t.Values[i].Value
}
query = groupByRe.ReplaceAllString(query, "GROUP BY time(:interval:)")
if pts, ok := tv["points"]; ok {
points, err := strconv.ParseInt(pts, 0, 64)
if err != nil {
@ -77,27 +82,6 @@ func RenderTemplate(query string, t chronograf.TemplateVar, now time.Time) (stri
return strings.Replace(query, t.Var, interval, -1), nil
}
if res, ok := tv["resolution"]; ok {
resolution, err := strconv.ParseInt(res, 0, 64)
if err != nil {
return "", err
}
ppp, ok := tv["pointsPerPixel"]
if !ok {
ppp = "3"
}
pixelsPerPoint, err := strconv.ParseInt(ppp, 0, 64)
if err != nil {
return "", err
}
dur, err := ParseTime(query, now)
if err != nil {
return "", err
}
interval := AutoGroupBy(resolution, pixelsPerPoint, dur)
return strings.Replace(query, t.Var, interval, -1), nil
}
return query, nil
}
@ -117,24 +101,6 @@ func AutoInterval(points int64, duration time.Duration) string {
return strconv.FormatInt(int64(secPerPixel), 10) + "s"
}
// AutoGroupBy generates the time to group by in order to decimate the number of
// points returned in a query
func AutoGroupBy(resolution, pixelsPerPoint int64, duration time.Duration) string {
// The function is: ((total_seconds * millisecond_converstion) / group_by) = pixels / 3
// Number of points given the pixels
pixels := float64(resolution) / float64(pixelsPerPoint)
msPerPixel := float64(duration/time.Millisecond) / pixels
secPerPixel := float64(duration/time.Second) / pixels
if secPerPixel < 1.0 {
if msPerPixel < 1.0 {
msPerPixel = 1.0
}
return "time(" + strconv.FormatInt(int64(msPerPixel), 10) + "ms)"
}
// If groupby is more than 1 second round to the second
return "time(" + strconv.FormatInt(int64(secPerPixel), 10) + "s)"
}
// TemplateReplace replaces templates with values within the query string
func TemplateReplace(query string, templates []chronograf.TemplateVar, now time.Time) (string, error) {
templates = SortTemplates(templates)

View File

@ -165,17 +165,13 @@ func TestTemplateReplace(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "999",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "333",
Type: "points",
},
},
},
},
want: `SELECT mean(usage_idle) from "cpu" where time > now() - 4320h group by time(46702s)`,
want: `SELECT mean(usage_idle) from "cpu" where time > now() - 4320h GROUP BY time(46702s)`,
},
{
name: "auto group by without duration",
@ -185,17 +181,13 @@ func TestTemplateReplace(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "999",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "333",
Type: "points",
},
},
},
},
want: `SELECT mean(usage_idle) from "cpu" WHERE time > now() - 4320h group by time(46702s)`,
want: `SELECT mean(usage_idle) from "cpu" WHERE time > now() - 4320h GROUP BY time(46702s)`,
},
{
name: "auto group by with :dashboardTime:",
@ -205,12 +197,8 @@ func TestTemplateReplace(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "1000",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "333",
Type: "points",
},
},
},
@ -224,7 +212,7 @@ func TestTemplateReplace(t *testing.T) {
},
},
},
want: `SELECT mean(usage_idle) from "cpu" WHERE time > now() - 4320h group by time(46655s)`,
want: `SELECT mean(usage_idle) from "cpu" WHERE time > now() - 4320h GROUP BY time(46702s)`,
},
{
name: "auto group by failing condition",
@ -234,12 +222,8 @@ func TestTemplateReplace(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "115",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "38",
Type: "points",
},
},
},
@ -254,7 +238,7 @@ func TestTemplateReplace(t *testing.T) {
},
},
},
want: `SELECT mean(usage_idle) FROM "cpu" WHERE time > now() - 1h GROUP BY time(93s)`,
want: `SELECT mean(usage_idle) FROM "cpu" WHERE time > now() - 1h GROUP BY time(94s)`,
},
{
name: "no template variables specified",
@ -269,12 +253,8 @@ func TestTemplateReplace(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "115",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "38",
Type: "points",
},
},
},
@ -289,7 +269,7 @@ func TestTemplateReplace(t *testing.T) {
},
},
},
want: `SELECT mean(usage_idle) FROM "cpu" WHERE time > now() - 1h GROUP BY time(93s)`,
want: `SELECT mean(usage_idle) FROM "cpu" WHERE time > now() - 1h GROUP BY time(94s)`,
},
{
name: "query with no template variables contained should return query",
@ -300,11 +280,7 @@ func TestTemplateReplace(t *testing.T) {
Values: []chronograf.TemplateValue{
{
Value: "115",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Type: "points",
},
},
},
@ -345,12 +321,8 @@ func Test_TemplateVarsUnmarshalling(t *testing.T) {
"tempVar": ":interval:",
"values": [
{
"value": "1000",
"type": "resolution"
},
{
"value": "3",
"type": "pointsPerPixel"
"value": "333",
"type": "points"
},
{
"value": "10",
@ -375,12 +347,8 @@ func Test_TemplateVarsUnmarshalling(t *testing.T) {
Var: ":interval:",
Values: []chronograf.TemplateValue{
{
Value: "1000",
Type: "resolution",
},
{
Value: "3",
Type: "pointsPerPixel",
Value: "333",
Type: "points",
},
{
Value: "10",
@ -411,46 +379,6 @@ func Test_TemplateVarsUnmarshalling(t *testing.T) {
}
}
func TestAutoGroupBy(t *testing.T) {
tests := []struct {
name string
resolution int64
pixelsPerPoint int64
duration time.Duration
want string
}{
{
name: "String() calculates the GROUP BY interval",
resolution: 700,
pixelsPerPoint: 3,
duration: 24 * time.Hour,
want: "time(370s)",
},
{
name: "String() milliseconds if less than one second intervals",
resolution: 100000,
pixelsPerPoint: 3,
duration: time.Hour,
want: "time(107ms)",
},
{
name: "String() milliseconds if less than one millisecond",
resolution: 100000,
pixelsPerPoint: 3,
duration: time.Second,
want: "time(1ms)",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := AutoGroupBy(tt.resolution, tt.pixelsPerPoint, tt.duration)
if got != tt.want {
t.Errorf("TestAutoGroupBy %s =\n%s\nwant\n%s", tt.name, got, tt.want)
}
})
}
}
func Test_RenderTemplate(t *testing.T) {
gbvTests := []struct {
name string
@ -461,37 +389,37 @@ func Test_RenderTemplate(t *testing.T) {
{
name: "relative time only lower bound with one day of duration",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d GROUP BY :interval:",
resolution: 1000,
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d GROUP BY time(259s)",
},
{
name: "relative time offset by week",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d - 7d AND time < now() - 7d GROUP BY :interval:",
resolution: 1000,
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d - 7d AND time < now() - 7d GROUP BY time(259s)",
},
{
name: "relative time with relative upper bound with one minute of duration",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 3m AND time < now() - 2m GROUP BY :interval:",
resolution: 1000,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 3m AND time < now() - 2m GROUP BY time(179ms)",
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 3m AND time < now() - 2m GROUP BY time(180ms)",
},
{
name: "relative time with relative lower bound and now upper with one day of duration",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d AND time < now() GROUP BY :interval:",
resolution: 1000,
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > now() - 1d AND time < now() GROUP BY time(259s)",
},
{
name: "absolute time with one minute of duration",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > '1985-10-25T00:01:00Z' and time < '1985-10-25T00:02:00Z' GROUP BY :interval:",
resolution: 1000,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > '1985-10-25T00:01:00Z' and time < '1985-10-25T00:02:00Z' GROUP BY time(179ms)",
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > '1985-10-25T00:01:00Z' and time < '1985-10-25T00:02:00Z' GROUP BY time(180ms)",
},
{
name: "absolute time with nano seconds and zero duration",
query: "SELECT mean(usage_idle) FROM cpu WHERE time > '2017-07-24T15:33:42.994Z' and time < '2017-07-24T15:33:42.994Z' GROUP BY :interval:",
resolution: 1000,
resolution: 333,
want: "SELECT mean(usage_idle) FROM cpu WHERE time > '2017-07-24T15:33:42.994Z' and time < '2017-07-24T15:33:42.994Z' GROUP BY time(1ms)",
},
{
@ -512,7 +440,7 @@ func Test_RenderTemplate(t *testing.T) {
Values: []chronograf.TemplateValue{
{
Value: fmt.Sprintf("%d", tt.resolution),
Type: "resolution",
Type: "points",
},
},
}

View File

@ -155,18 +155,14 @@ func TestService_Queries(t *testing.T) {
"tempVar": ":interval:",
"values": [
{
"value": "1000",
"type": "resolution"
},
{
"value": "3",
"type": "pointsPerPixel"
"value": "333",
"type": "points"
}
]
}
]
}`))),
want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","range":null,"shifts":[]},"queryTemplated":"SELECT \"pingReq\" FROM \"_internal\".\"monitor\".\"httpd\" WHERE time \u003e now() - 15m AND time \u003c now() GROUP BY time(2s)","tempVars":[{"tempVar":":upperDashboardTime:","values":[{"value":"now()","type":"constant","selected":true}]},{"tempVar":":dashboardTime:","values":[{"value":"now() - 15m","type":"constant","selected":true}]},{"tempVar":":dbs:","values":[{"value":"_internal","type":"database","selected":true}]},{"tempVar":":interval:","values":[{"value":"1000","type":"resolution","selected":false},{"value":"3","type":"pointsPerPixel","selected":false}]}]}]}
want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","range":null,"shifts":[]},"queryTemplated":"SELECT \"pingReq\" FROM \"_internal\".\"monitor\".\"httpd\" WHERE time \u003e now() - 15m AND time \u003c now() GROUP BY time(2s)","tempVars":[{"tempVar":":upperDashboardTime:","values":[{"value":"now()","type":"constant","selected":true}]},{"tempVar":":dashboardTime:","values":[{"value":"now() - 15m","type":"constant","selected":true}]},{"tempVar":":dbs:","values":[{"value":"_internal","type":"database","selected":true}]},{"tempVar":":interval:","values":[{"value":"333","type":"points","selected":false}]}]}]}
`,
},
}