Skip to content

Commit

Permalink
Keep the existing behaviour as default
Browse files Browse the repository at this point in the history
Signed-off-by: Kemal Akkoyun <[email protected]>
  • Loading branch information
kakkoyun committed Sep 14, 2020
1 parent a950d74 commit d57d8bc
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 71 deletions.
2 changes: 1 addition & 1 deletion cmd/thanos/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func registerQuery(app *extkingpin.App) {

instantDefaultMaxSourceResolution := modelDuration(cmd.Flag("query.instant.default.max_source_resolution", "default value for max_source_resolution for instant queries. If not set, defaults to 0s only taking raw resolution into account. 1h can be a good value if you use instant queries over time ranges that incorporate times outside of your raw-retention.").Default("0s").Hidden())

defaultLabelLookbackDelta := cmd.Flag("query.labels.lookback-delta", "The default lookback duration for retrieving labels through Labels API when the range parameters are not specified.").Default("2h").Duration()
defaultLabelLookbackDelta := cmd.Flag("query.labels.api-lookback-delta", "The default lookback duration for retrieving labels through Labels API when the range parameters are not specified. The zero value means range covers the time since the beginning.").Default("0s").Duration()

selectorLabels := cmd.Flag("selector-label", "Query selector labels that will be exposed in info endpoint (repeated).").
PlaceHolder("<name>=\"<value>\"").Strings()
Expand Down
6 changes: 4 additions & 2 deletions docs/components/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,12 @@ Flags:
able to query without deduplication using
'dedup=false' parameter. Data includes time
series, recording rules, and alerting rules.
--query.labels.lookback-delta=2h
--query.labels.api-lookback-delta=0s
The default lookback duration for retrieving
labels through Labels API when the range
parameters are not specified.
parameters are not specified. The zero value
means range covers the time since the
beginning.
--selector-label=<name>="<value>" ...
Query selector labels that will be exposed in
info endpoint (repeated).
Expand Down
143 changes: 75 additions & 68 deletions pkg/api/query/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,20 +422,10 @@ func (qapi *QueryAPI) labelValues(r *http.Request) (interface{}, []error, *api.A
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid label name: %q", name)}
}

// If start and end time not specified, we get the last 2h window by default.
now := time.Now()
start, err := parseTimeParam(r, "start", now.Add(-qapi.defaultLabelLookbackDelta))
start, end, err := parseLabelTimeRange(r, qapi.defaultLabelLookbackDelta)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
end, err := parseTimeParam(r, "end", now)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
if end.Before(start) {
err := errors.New("end timestamp must not be before start time")
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}

enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
if apiErr != nil {
Expand Down Expand Up @@ -468,11 +458,6 @@ func (qapi *QueryAPI) labelValues(r *http.Request) (interface{}, []error, *api.A
return vals, warnings, nil
}

var (
minTime = time.Unix(math.MinInt64/1000+62135596801, 0)
maxTime = time.Unix(math.MaxInt64/1000-62135596801, 999999999)
)

func (qapi *QueryAPI) series(r *http.Request) (interface{}, []error, *api.ApiError) {
if err := r.ParseForm(); err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "parse form")}
Expand Down Expand Up @@ -549,61 +534,11 @@ func (qapi *QueryAPI) series(r *http.Request) (interface{}, []error, *api.ApiErr
return metrics, set.Warnings(), nil
}

func parseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) {
val := r.FormValue(paramName)
if val == "" {
return defaultValue, nil
}
result, err := parseTime(val)
if err != nil {
return time.Time{}, errors.Wrapf(err, "Invalid time value for '%s'", paramName)
}
return result, nil
}

func parseTime(s string) (time.Time, error) {
if t, err := strconv.ParseFloat(s, 64); err == nil {
s, ns := math.Modf(t)
ns = math.Round(ns*1000) / 1000
return time.Unix(int64(s), int64(ns*float64(time.Second))), nil
}
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
return t, nil
}
return time.Time{}, errors.Errorf("cannot parse %q to a valid timestamp", s)
}

func parseDuration(s string) (time.Duration, error) {
if d, err := strconv.ParseFloat(s, 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", s)
}
return time.Duration(ts), nil
}
if d, err := model.ParseDuration(s); err == nil {
return time.Duration(d), nil
}
return 0, errors.Errorf("cannot parse %q to a valid duration", s)
}

func (qapi *QueryAPI) labelNames(r *http.Request) (interface{}, []error, *api.ApiError) {
ctx := r.Context()

// If start and end time not specified, we get the last 2h window by default.
now := time.Now()
start, err := parseTimeParam(r, "start", now.Add(-qapi.defaultLabelLookbackDelta))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
end, err := parseTimeParam(r, "end", now)
start, end, err := parseLabelTimeRange(r, qapi.defaultLabelLookbackDelta)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
if end.Before(start) {
err := errors.New("end timestamp must not be before start time")
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}

enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
if apiErr != nil {
Expand All @@ -615,7 +550,8 @@ func (qapi *QueryAPI) labelNames(r *http.Request) (interface{}, []error, *api.Ap
return nil, nil, apiErr
}

q, err := qapi.queryableCreate(true, nil, storeMatchers, 0, enablePartialResponse, false).Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end))
q, err := qapi.queryableCreate(true, nil, storeMatchers, 0, enablePartialResponse, false).
Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err}
}
Expand Down Expand Up @@ -667,3 +603,74 @@ func NewRulesHandler(client rules.UnaryClient, enablePartialResponse bool) func(
return groups, warnings, nil
}
}

var (
minTime = time.Unix(math.MinInt64/1000+62135596801, 0)
maxTime = time.Unix(math.MaxInt64/1000-62135596801, 999999999)
)

func parseLabelTimeRange(r *http.Request, defaultLabelLookbackDelta time.Duration) (time.Time, time.Time, error) {
// If start and end time not specified as query parameter, we get the range from the beginning of time by default.
var defaultStart, defaultEnd time.Time
if defaultLabelLookbackDelta == 0 {
defaultStart = minTime
defaultEnd = maxTime
} else {
now := time.Now()
defaultStart = now.Add(-defaultLabelLookbackDelta)
defaultEnd = now
}

start, err := parseTimeParam(r, "start", defaultStart)
if err != nil {
return time.Time{}, time.Time{}, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
end, err := parseTimeParam(r, "end", defaultEnd)
if err != nil {
return time.Time{}, time.Time{}, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}
if end.Before(start) {
err := errors.New("end timestamp must not be before start time")
return time.Time{}, time.Time{}, &api.ApiError{Typ: api.ErrorBadData, Err: err}
}

return start, end, nil
}

func parseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) {
val := r.FormValue(paramName)
if val == "" {
return defaultValue, nil
}
result, err := parseTime(val)
if err != nil {
return time.Time{}, errors.Wrapf(err, "Invalid time value for '%s'", paramName)
}
return result, nil
}

func parseTime(s string) (time.Time, error) {
if t, err := strconv.ParseFloat(s, 64); err == nil {
s, ns := math.Modf(t)
ns = math.Round(ns*1000) / 1000
return time.Unix(int64(s), int64(ns*float64(time.Second))), nil
}
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
return t, nil
}
return time.Time{}, errors.Errorf("cannot parse %q to a valid timestamp", s)
}

func parseDuration(s string) (time.Duration, error) {
if d, err := strconv.ParseFloat(s, 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", s)
}
return time.Duration(ts), nil
}
if d, err := model.ParseDuration(s); err == nil {
return time.Duration(d), nil
}
return 0, errors.Errorf("cannot parse %q to a valid duration", s)
}

0 comments on commit d57d8bc

Please sign in to comment.