Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP API: Support duration and float formats for step parameter #1355

Merged
merged 3 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ accepts the following query parameters in the URL:
- `limit`: The max number of entries to return
- `start`: The start time for the query as a nanosecond Unix epoch. Defaults to one hour ago.
- `end`: The start time for the query as a nanosecond Unix epoch. Defaults to now.
- `step`: Query resolution step width in seconds. Defaults to a dynamic value based on `start` and `end`.
- `step`: Query resolution step width in `duration` format or float number of seconds. `duration` refers to Prometheus duration strings of the form `[0-9]+[smhdwy]`. For example, 5m refers to a duration of 5 minutes. Defaults to a dynamic value based on `start` and `end`.
- `direction`: Determines the sort order of logs. Supported values are `forward` or `backward`. Defaults to `backward.`

Requests against this endpoint require Loki to query the index store in order to
Expand Down
22 changes: 18 additions & 4 deletions pkg/loghttp/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
"strings"
"time"

"github.com/pkg/errors"
"github.com/prometheus/common/model"

"github.com/grafana/loki/pkg/logproto"
)

Expand Down Expand Up @@ -50,11 +53,22 @@ func bounds(r *http.Request) (time.Time, time.Time, error) {
}

func step(r *http.Request, start, end time.Time) (time.Duration, error) {
s, err := parseInt(r.URL.Query().Get("step"), defaultQueryRangeStep(start, end))
if err != nil {
return 0, err
value := r.URL.Query().Get("step")
if value == "" {
return time.Duration(defaultQueryRangeStep(start, end)) * time.Second, nil
}

if d, err := strconv.ParseFloat(value, 64); err == nil {
ts := d * float64(time.Second)
if ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {
return 0, errors.Errorf("cannot parse %q to a valid duration. It overflows int64", value)
}
return time.Duration(ts), nil
}
if d, err := model.ParseDuration(value); err == nil {
return time.Duration(d), nil
}
return time.Duration(s) * time.Second, nil
return 0, errors.Errorf("cannot parse %q to a valid duration", value)
}

// defaultQueryRangeStep returns the default step used in the query range API,
Expand Down
46 changes: 45 additions & 1 deletion pkg/loghttp/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestHttp_ParseRangeQuery_Step(t *testing.T) {
Direction: logproto.BACKWARD,
},
},
"should use the input step parameter if provided": {
"should use the input step parameter if provided as an integer": {
reqPath: "/loki/api/v1/query_range?query={}&start=0&end=3600000000000&step=5",
expected: &RangeQuery{
Query: "{}",
Expand All @@ -74,6 +74,50 @@ func TestHttp_ParseRangeQuery_Step(t *testing.T) {
Direction: logproto.BACKWARD,
},
},
"should use the input step parameter if provided as a float without decimals": {
reqPath: "/loki/api/v1/query_range?query={}&start=0&end=3600000000000&step=5.000",
expected: &RangeQuery{
Query: "{}",
Start: time.Unix(0, 0),
End: time.Unix(3600, 0),
Step: 5 * time.Second,
Limit: 100,
Direction: logproto.BACKWARD,
},
},
"should use the input step parameter if provided as a float with decimals": {
reqPath: "/loki/api/v1/query_range?query={}&start=0&end=3600000000000&step=5.500",
expected: &RangeQuery{
Query: "{}",
Start: time.Unix(0, 0),
End: time.Unix(3600, 0),
Step: 5.5 * 1e9,
Limit: 100,
Direction: logproto.BACKWARD,
},
},
"should use the input step parameter if provided as a duration in seconds": {
reqPath: "/loki/api/v1/query_range?query={}&start=0&end=3600000000000&step=5s",
expected: &RangeQuery{
Query: "{}",
Start: time.Unix(0, 0),
End: time.Unix(3600, 0),
Step: 5 * time.Second,
Limit: 100,
Direction: logproto.BACKWARD,
},
},
"should use the input step parameter if provided as a duration in days": {
reqPath: "/loki/api/v1/query_range?query={}&start=0&end=3600000000000&step=5d",
expected: &RangeQuery{
Query: "{}",
Start: time.Unix(0, 0),
End: time.Unix(3600, 0),
Step: 5 * 24 * 3600 * time.Second,
Limit: 100,
Direction: logproto.BACKWARD,
},
},
}

for testName, testData := range tests {
Expand Down