vmalert:fix query request using rfc3339 format (#4577)

vmalert: consistently use time.RFC3339 format for time in queries

Co-authored-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
Haleygo 2023-07-07 16:39:25 +08:00 committed by GitHub
parent 1df3e548c1
commit bca8ae034f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 32 deletions

View file

@ -168,7 +168,7 @@ func (s *VMStorage) setPrometheusInstantReqParams(r *http.Request, query string,
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1232 // see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1232
timestamp = timestamp.Truncate(s.evaluationInterval) timestamp = timestamp.Truncate(s.evaluationInterval)
} }
q.Set("time", fmt.Sprintf("%d", timestamp.Unix())) q.Set("time", timestamp.Format(time.RFC3339))
if !*disableStepParam && s.evaluationInterval > 0 { // set step as evaluationInterval by default if !*disableStepParam && s.evaluationInterval > 0 { // set step as evaluationInterval by default
// always convert to seconds to keep compatibility with older // always convert to seconds to keep compatibility with older
// Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943 // Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943
@ -191,8 +191,8 @@ func (s *VMStorage) setPrometheusRangeReqParams(r *http.Request, query string, s
r.URL.Path += "/api/v1/query_range" r.URL.Path += "/api/v1/query_range"
} }
q := r.URL.Query() q := r.URL.Query()
q.Add("start", fmt.Sprintf("%d", start.Unix())) q.Add("start", start.Format(time.RFC3339))
q.Add("end", fmt.Sprintf("%d", end.Unix())) q.Add("end", end.Format(time.RFC3339))
if s.evaluationInterval > 0 { // set step as evaluationInterval by default if s.evaluationInterval > 0 { // set step as evaluationInterval by default
// always convert to seconds to keep compatibility with older // always convert to seconds to keep compatibility with older
// Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943 // Prometheus versions. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1943

View file

@ -8,7 +8,6 @@ import (
"net/url" "net/url"
"reflect" "reflect"
"sort" "sort"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -50,8 +49,8 @@ func TestVMInstantQuery(t *testing.T) {
if timeParam == "" { if timeParam == "" {
t.Errorf("expected 'time' in query param, got nil instead") t.Errorf("expected 'time' in query param, got nil instead")
} }
if _, err := strconv.ParseInt(timeParam, 10, 64); err != nil { if _, err := time.Parse(time.RFC3339, timeParam); err != nil {
t.Errorf("failed to parse 'time' query param: %s", err) t.Errorf("failed to parse 'time' query param %q: %s", timeParam, err)
} }
switch c { switch c {
case 0: case 0:
@ -193,7 +192,6 @@ func TestVMInstantQuery(t *testing.T) {
}, },
} }
metricsEqual(t, res.Data, exp) metricsEqual(t, res.Data, exp)
} }
func TestVMInstantQueryWithRetry(t *testing.T) { func TestVMInstantQueryWithRetry(t *testing.T) {
@ -309,14 +307,14 @@ func TestVMRangeQuery(t *testing.T) {
if startTS == "" { if startTS == "" {
t.Errorf("expected 'start' in query param, got nil instead") t.Errorf("expected 'start' in query param, got nil instead")
} }
if _, err := strconv.ParseInt(startTS, 10, 64); err != nil { if _, err := time.Parse(time.RFC3339, startTS); err != nil {
t.Errorf("failed to parse 'start' query param: %s", err) t.Errorf("failed to parse 'start' query param: %s", err)
} }
endTS := r.URL.Query().Get("end") endTS := r.URL.Query().Get("end")
if endTS == "" { if endTS == "" {
t.Errorf("expected 'end' in query param, got nil instead") t.Errorf("expected 'end' in query param, got nil instead")
} }
if _, err := strconv.ParseInt(endTS, 10, 64); err != nil { if _, err := time.Parse(time.RFC3339, endTS); err != nil {
t.Errorf("failed to parse 'end' query param: %s", err) t.Errorf("failed to parse 'end' query param: %s", err)
} }
step := r.URL.Query().Get("step") step := r.URL.Query().Get("step")
@ -455,8 +453,8 @@ func TestRequestParams(t *testing.T) {
false, false,
&VMStorage{}, &VMStorage{},
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("query=%s&time=%d", query, timestamp.Unix()) exp := url.Values{"query": {query}, "time": {timestamp.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -464,8 +462,9 @@ func TestRequestParams(t *testing.T) {
true, true,
&VMStorage{}, &VMStorage{},
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("end=%d&query=%s&start=%d", timestamp.Unix(), query, timestamp.Unix()) ts := timestamp.Format(time.RFC3339)
checkEqualString(t, exp, r.URL.RawQuery) exp := url.Values{"query": {query}, "start": {ts}, "end": {ts}}
checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -495,8 +494,8 @@ func TestRequestParams(t *testing.T) {
lookBack: time.Minute, lookBack: time.Minute,
}, },
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("query=%s&time=%d", query, timestamp.Add(-time.Minute).Unix()) exp := url.Values{"query": {query}, "time": {timestamp.Add(-time.Minute).Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -508,8 +507,8 @@ func TestRequestParams(t *testing.T) {
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
evalInterval := 15 * time.Second evalInterval := 15 * time.Second
tt := timestamp.Truncate(evalInterval) tt := timestamp.Truncate(evalInterval)
exp := fmt.Sprintf("query=%s&step=%v&time=%d", query, evalInterval, tt.Unix()) exp := url.Values{"query": {query}, "step": {evalInterval.String()}, "time": {tt.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -523,8 +522,8 @@ func TestRequestParams(t *testing.T) {
evalInterval := 15 * time.Second evalInterval := 15 * time.Second
tt := timestamp.Add(-time.Minute) tt := timestamp.Add(-time.Minute)
tt = tt.Truncate(evalInterval) tt = tt.Truncate(evalInterval)
exp := fmt.Sprintf("query=%s&step=%v&time=%d", query, evalInterval, tt.Unix()) exp := url.Values{"query": {query}, "step": {evalInterval.String()}, "time": {tt.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -534,8 +533,12 @@ func TestRequestParams(t *testing.T) {
queryStep: time.Minute, queryStep: time.Minute,
}, },
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("query=%s&step=%ds&time=%d", query, int(time.Minute.Seconds()), timestamp.Unix()) exp := url.Values{
checkEqualString(t, exp, r.URL.RawQuery) "query": {query},
"step": {fmt.Sprintf("%ds", int(time.Minute.Seconds()))},
"time": {timestamp.Format(time.RFC3339)},
}
checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -547,8 +550,8 @@ func TestRequestParams(t *testing.T) {
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
evalInterval := 3 * time.Hour evalInterval := 3 * time.Hour
tt := timestamp.Truncate(evalInterval) tt := timestamp.Truncate(evalInterval)
exp := fmt.Sprintf("query=%s&step=%ds&time=%d", query, int(evalInterval.Seconds()), tt.Unix()) exp := url.Values{"query": {query}, "step": {fmt.Sprintf("%ds", int(evalInterval.Seconds()))}, "time": {tt.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -558,8 +561,8 @@ func TestRequestParams(t *testing.T) {
extraParams: url.Values{"round_digits": {"10"}}, extraParams: url.Values{"round_digits": {"10"}},
}, },
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("query=%s&round_digits=10&time=%d", query, timestamp.Unix()) exp := url.Values{"query": {query}, "round_digits": {"10"}, "time": {timestamp.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -572,9 +575,14 @@ func TestRequestParams(t *testing.T) {
}, },
}, },
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("end=%d&max_lookback=1h&nocache=1&query=%s&start=%d", exp := url.Values{
timestamp.Unix(), query, timestamp.Unix()) "query": {query},
checkEqualString(t, exp, r.URL.RawQuery) "end": {timestamp.Format(time.RFC3339)},
"start": {timestamp.Format(time.RFC3339)},
"nocache": {"1"},
"max_lookback": {"1h"},
}
checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -584,8 +592,8 @@ func TestRequestParams(t *testing.T) {
QueryParams: url.Values{"round_digits": {"2"}}, QueryParams: url.Values{"round_digits": {"2"}},
}), }),
func(t *testing.T, r *http.Request) { func(t *testing.T, r *http.Request) {
exp := fmt.Sprintf("query=%s&round_digits=2&time=%d", query, timestamp.Unix()) exp := url.Values{"query": {query}, "round_digits": {"2"}, "time": {timestamp.Format(time.RFC3339)}}
checkEqualString(t, exp, r.URL.RawQuery) checkEqualString(t, exp.Encode(), r.URL.RawQuery)
}, },
}, },
{ {
@ -627,7 +635,7 @@ func TestRequestParams(t *testing.T) {
} }
func TestHeaders(t *testing.T) { func TestHeaders(t *testing.T) {
var testCases = []struct { testCases := []struct {
name string name string
vmFn func() *VMStorage vmFn func() *VMStorage
checkFn func(t *testing.T, r *http.Request) checkFn func(t *testing.T, r *http.Request)
@ -692,7 +700,8 @@ func TestHeaders(t *testing.T) {
authCfg: cfg, authCfg: cfg,
extraHeaders: []keyValue{ extraHeaders: []keyValue{
{key: "Authorization", value: "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, {key: "Authorization", value: "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="},
}} },
}
}, },
checkFn: func(t *testing.T, r *http.Request) { checkFn: func(t *testing.T, r *http.Request) {
u, p, _ := r.BasicAuth() u, p, _ := r.BasicAuth()

View file

@ -49,6 +49,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix application routing issues and problems with manual URL changes. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4408). * BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix application routing issues and problems with manual URL changes. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4408).
* BUGFIX: add validation for invalid [partial RFC3339 timestamp formats](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#timestamp-formats) in query and export APIs. * BUGFIX: add validation for invalid [partial RFC3339 timestamp formats](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#timestamp-formats) in query and export APIs.
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl.html): interrupt explore procedure in influx mode if vmctl found no numeric fields. * BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl.html): interrupt explore procedure in influx mode if vmctl found no numeric fields.
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): use RFC3339 time format in query args instead of unix timestamp for all issued queries to Prometheus-like datasources.
## [v1.91.3](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.91.3) ## [v1.91.3](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.91.3)