mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-20 15:16:42 +00:00
vmalert: support scalar
type in response (#2610)
See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2607 Signed-off-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
a07ddf9b65
commit
2aeb00f98f
5 changed files with 75 additions and 34 deletions
|
@ -69,7 +69,7 @@ test-vmalert:
|
||||||
go test -v -race -cover ./app/vmalert/remotewrite
|
go test -v -race -cover ./app/vmalert/remotewrite
|
||||||
|
|
||||||
run-vmalert: vmalert
|
run-vmalert: vmalert
|
||||||
./bin/vmalert -rule=app/vmalert/config/testdata/rules2-good.rules \
|
./bin/vmalert -rule=app/vmalert/config/testdata/rules/rules2-good.rules \
|
||||||
-datasource.url=http://localhost:8428 \
|
-datasource.url=http://localhost:8428 \
|
||||||
-notifier.url=http://localhost:9093 \
|
-notifier.url=http://localhost:9093 \
|
||||||
-notifier.url=http://127.0.0.1:9093 \
|
-notifier.url=http://127.0.0.1:9093 \
|
||||||
|
@ -78,7 +78,7 @@ run-vmalert: vmalert
|
||||||
-external.label=cluster=east-1 \
|
-external.label=cluster=east-1 \
|
||||||
-external.label=replica=a \
|
-external.label=replica=a \
|
||||||
-evaluationInterval=3s \
|
-evaluationInterval=3s \
|
||||||
-rule.configCheckInterval=10s
|
-configCheckInterval=10s
|
||||||
|
|
||||||
run-vmalert-sd: vmalert
|
run-vmalert-sd: vmalert
|
||||||
./bin/vmalert -rule=app/vmalert/config/testdata/rules2-good.rules \
|
./bin/vmalert -rule=app/vmalert/config/testdata/rules2-good.rules \
|
||||||
|
|
|
@ -2,8 +2,6 @@ groups:
|
||||||
- name: TestGroup
|
- name: TestGroup
|
||||||
interval: 2s
|
interval: 2s
|
||||||
concurrency: 2
|
concurrency: 2
|
||||||
extra_filter_labels: # deprecated param, use `params` instead
|
|
||||||
job: victoriametrics
|
|
||||||
params:
|
params:
|
||||||
denyPartialResponse: ["true"]
|
denyPartialResponse: ["true"]
|
||||||
extra_label: ["env=dev"]
|
extra_label: ["env=dev"]
|
||||||
|
@ -49,4 +47,12 @@ groups:
|
||||||
expr: |2
|
expr: |2
|
||||||
sum(code:requests:rate5m{code="200"})
|
sum(code:requests:rate5m{code="200"})
|
||||||
/
|
/
|
||||||
sum(code:requests:rate5m)
|
sum(code:requests:rate5m)
|
||||||
|
- record: code:requests:slo
|
||||||
|
labels:
|
||||||
|
recording: true
|
||||||
|
expr: 0.95
|
||||||
|
- record: time:current
|
||||||
|
labels:
|
||||||
|
recording: true
|
||||||
|
expr: time()
|
|
@ -31,13 +31,6 @@ type promInstant struct {
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type promRange struct {
|
|
||||||
Result []struct {
|
|
||||||
Labels map[string]string `json:"metric"`
|
|
||||||
TVs [][2]interface{} `json:"values"`
|
|
||||||
} `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r promInstant) metrics() ([]Metric, error) {
|
func (r promInstant) metrics() ([]Metric, error) {
|
||||||
var result []Metric
|
var result []Metric
|
||||||
for i, res := range r.Result {
|
for i, res := range r.Result {
|
||||||
|
@ -56,6 +49,13 @@ func (r promInstant) metrics() ([]Metric, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type promRange struct {
|
||||||
|
Result []struct {
|
||||||
|
Labels map[string]string `json:"metric"`
|
||||||
|
TVs [][2]interface{} `json:"values"`
|
||||||
|
} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
func (r promRange) metrics() ([]Metric, error) {
|
func (r promRange) metrics() ([]Metric, error) {
|
||||||
var result []Metric
|
var result []Metric
|
||||||
for i, res := range r.Result {
|
for i, res := range r.Result {
|
||||||
|
@ -80,9 +80,22 @@ func (r promRange) metrics() ([]Metric, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type promScalar [2]interface{}
|
||||||
|
|
||||||
|
func (r promScalar) metrics() ([]Metric, error) {
|
||||||
|
var m Metric
|
||||||
|
f, err := strconv.ParseFloat(r[1].(string), 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("metric %v, unable to parse float64 from %s: %w", r, r[1], err)
|
||||||
|
}
|
||||||
|
m.Values = append(m.Values, f)
|
||||||
|
m.Timestamps = append(m.Timestamps, int64(r[0].(float64)))
|
||||||
|
return []Metric{m}, nil
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
statusSuccess, statusError = "success", "error"
|
statusSuccess, statusError = "success", "error"
|
||||||
rtVector, rtMatrix = "vector", "matrix"
|
rtVector, rtMatrix, rScalar = "vector", "matrix", "scalar"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parsePrometheusResponse(req *http.Request, resp *http.Response) ([]Metric, error) {
|
func parsePrometheusResponse(req *http.Request, resp *http.Response) ([]Metric, error) {
|
||||||
|
@ -109,7 +122,14 @@ func parsePrometheusResponse(req *http.Request, resp *http.Response) ([]Metric,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pr.metrics()
|
return pr.metrics()
|
||||||
|
case rScalar:
|
||||||
|
var ps promScalar
|
||||||
|
if err := json.Unmarshal(r.Data.Result, &ps); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ps.metrics()
|
||||||
default:
|
default:
|
||||||
|
fmt.Println(string(r.Data.Result))
|
||||||
return nil, fmt.Errorf("unknown result type %q", r.Data.ResultType)
|
return nil, fmt.Errorf("unknown result type %q", r.Data.ResultType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestVMInstantQuery(t *testing.T) {
|
||||||
mux.HandleFunc("/render", func(w http.ResponseWriter, request *http.Request) {
|
mux.HandleFunc("/render", func(w http.ResponseWriter, request *http.Request) {
|
||||||
c++
|
c++
|
||||||
switch c {
|
switch c {
|
||||||
case 7:
|
case 8:
|
||||||
w.Write([]byte(`[{"target":"constantLine(10)","tags":{"name":"constantLine(10)"},"datapoints":[[10,1611758343],[10,1611758373],[10,1611758403]]}]`))
|
w.Write([]byte(`[{"target":"constantLine(10)","tags":{"name":"constantLine(10)"},"datapoints":[[10,1611758343],[10,1611758373],[10,1611758403]]}]`))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -75,6 +75,8 @@ func TestVMInstantQuery(t *testing.T) {
|
||||||
w.Write([]byte(`{"status":"success","data":{"resultType":"matrix"}}`))
|
w.Write([]byte(`{"status":"success","data":{"resultType":"matrix"}}`))
|
||||||
case 6:
|
case 6:
|
||||||
w.Write([]byte(`{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"vm_rows"},"value":[1583786142,"13763"]},{"metric":{"__name__":"vm_requests"},"value":[1583786140,"2000"]}]}}`))
|
w.Write([]byte(`{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"vm_rows"},"value":[1583786142,"13763"]},{"metric":{"__name__":"vm_requests"},"value":[1583786140,"2000"]}]}}`))
|
||||||
|
case 7:
|
||||||
|
w.Write([]byte(`{"status":"success","data":{"resultType":"scalar","result":[1583786142, "1"]}}`))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -91,25 +93,20 @@ func TestVMInstantQuery(t *testing.T) {
|
||||||
pq := s.BuildWithParams(QuerierParams{DataSourceType: &p, EvaluationInterval: 15 * time.Second})
|
pq := s.BuildWithParams(QuerierParams{DataSourceType: &p, EvaluationInterval: 15 * time.Second})
|
||||||
ts := time.Now()
|
ts := time.Now()
|
||||||
|
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
expErr := func(err string) {
|
||||||
t.Fatalf("expected connection error got nil")
|
if _, err := pq.Query(ctx, query, ts); err == nil {
|
||||||
|
t.Fatalf("expected %q got nil", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
|
||||||
t.Fatalf("expected invalid response status error got nil")
|
expErr("connection error") // 0
|
||||||
}
|
expErr("invalid response status error") // 1
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
expErr("response body error") // 2
|
||||||
t.Fatalf("expected response body error got nil")
|
expErr("error status") // 3
|
||||||
}
|
expErr("unknown status") // 4
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
expErr("non-vector resultType error") // 5
|
||||||
t.Fatalf("expected error status got nil")
|
|
||||||
}
|
m, err := pq.Query(ctx, query, ts) // 6 - vector
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
|
||||||
t.Fatalf("expected unknown status got nil")
|
|
||||||
}
|
|
||||||
if _, err := pq.Query(ctx, query, ts); err == nil {
|
|
||||||
t.Fatalf("expected non-vector resultType error got nil")
|
|
||||||
}
|
|
||||||
m, err := pq.Query(ctx, query, ts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected %s", err)
|
t.Fatalf("unexpected %s", err)
|
||||||
}
|
}
|
||||||
|
@ -132,10 +129,27 @@ func TestVMInstantQuery(t *testing.T) {
|
||||||
t.Fatalf("unexpected metric %+v want %+v", m, expected)
|
t.Fatalf("unexpected metric %+v want %+v", m, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m, err = pq.Query(ctx, query, ts) // 7 - scalar
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected %s", err)
|
||||||
|
}
|
||||||
|
if len(m) != 1 {
|
||||||
|
t.Fatalf("expected 1 metrics got %d in %+v", len(m), m)
|
||||||
|
}
|
||||||
|
expected = []Metric{
|
||||||
|
{
|
||||||
|
Timestamps: []int64{1583786142},
|
||||||
|
Values: []float64{1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(m, expected) {
|
||||||
|
t.Fatalf("unexpected metric %+v want %+v", m, expected)
|
||||||
|
}
|
||||||
|
|
||||||
g := NewGraphiteType()
|
g := NewGraphiteType()
|
||||||
gq := s.BuildWithParams(QuerierParams{DataSourceType: &g})
|
gq := s.BuildWithParams(QuerierParams{DataSourceType: &g})
|
||||||
|
|
||||||
m, err = gq.Query(ctx, queryRender, ts)
|
m, err = gq.Query(ctx, queryRender, ts) // 8 - graphite
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected %s", err)
|
t.Fatalf("unexpected %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
||||||
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): support [reusable templates](https://prometheus.io/docs/prometheus/latest/configuration/template_examples/#defining-reusable-templates) for rules annotations. The path to the template files can be specified via `-rule.templates` flag. See more about this feature [here](https://docs.victoriametrics.com/vmalert.html#reusable-templates). Thanks to @AndrewChubatiuk for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2532).
|
* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): support [reusable templates](https://prometheus.io/docs/prometheus/latest/configuration/template_examples/#defining-reusable-templates) for rules annotations. The path to the template files can be specified via `-rule.templates` flag. See more about this feature [here](https://docs.victoriametrics.com/vmalert.html#reusable-templates). Thanks to @AndrewChubatiuk for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2532).
|
||||||
* FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): add `influx-prometheus-mode` command-line flag, which allows to restore the original time series written from Prometheus into InfluxDB during data migration from InfluxDB to VictoriaMetrics. See [this feature request](https://github.com/VictoriaMetrics/vmctl/issues/8). Thanks to @mback2k for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2545).
|
* FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): add `influx-prometheus-mode` command-line flag, which allows to restore the original time series written from Prometheus into InfluxDB during data migration from InfluxDB to VictoriaMetrics. See [this feature request](https://github.com/VictoriaMetrics/vmctl/issues/8). Thanks to @mback2k for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2545).
|
||||||
|
|
||||||
|
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): support `scalar` result type in response. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2607.
|
||||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): support strings in `humanize.*` template function. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2569.
|
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): support strings in `humanize.*` template function. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2569.
|
||||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): proxy `/rules` requests to vmalert from Grafana's alerting UI. This removes errors in Grafana's UI for Grafana versions older than 8.5.*. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2583.
|
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): proxy `/rules` requests to vmalert from Grafana's alerting UI. This removes errors in Grafana's UI for Grafana versions older than 8.5.*. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2583.
|
||||||
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): do not return values from [label_value()](https://docs.victoriametrics.com/MetricsQL.html#label_value) function if the original time series has no values at the selected timestamps.
|
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): do not return values from [label_value()](https://docs.victoriametrics.com/MetricsQL.html#label_value) function if the original time series has no values at the selected timestamps.
|
||||||
|
|
Loading…
Reference in a new issue