mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
vmalert-tool: add more syntax checks for input_series
and exp_samples
(#7263)
address https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7224, allow using ``` exp_samples: - labels: '{}' ``` for prometheus compatibility. --------- Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
c90adf566e
commit
4984e71da6
4 changed files with 65 additions and 19 deletions
|
@ -43,18 +43,33 @@ func httpWrite(address string, r io.Reader) {
|
||||||
// writeInputSeries send input series to vmstorage and flush them
|
// writeInputSeries send input series to vmstorage and flush them
|
||||||
func writeInputSeries(input []series, interval *promutils.Duration, startStamp time.Time, dst string) error {
|
func writeInputSeries(input []series, interval *promutils.Duration, startStamp time.Time, dst string) error {
|
||||||
r := testutil.WriteRequest{}
|
r := testutil.WriteRequest{}
|
||||||
|
var err error
|
||||||
|
r.Timeseries, err = parseInputSeries(input, interval, startStamp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := testutil.Compress(r)
|
||||||
|
// write input series to vm
|
||||||
|
httpWrite(dst, bytes.NewBuffer(data))
|
||||||
|
vmstorage.Storage.DebugFlush()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInputSeries(input []series, interval *promutils.Duration, startStamp time.Time) ([]testutil.TimeSeries, error) {
|
||||||
|
var res []testutil.TimeSeries
|
||||||
for _, data := range input {
|
for _, data := range input {
|
||||||
expr, err := metricsql.Parse(data.Series)
|
expr, err := metricsql.Parse(data.Series)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse series %s: %v", data.Series, err)
|
return res, fmt.Errorf("failed to parse series %s: %v", data.Series, err)
|
||||||
}
|
}
|
||||||
promvals, err := parseInputValue(data.Values, true)
|
promvals, err := parseInputValue(data.Values, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse input series value %s: %v", data.Values, err)
|
return res, fmt.Errorf("failed to parse input series value %s: %v", data.Values, err)
|
||||||
}
|
}
|
||||||
metricExpr, ok := expr.(*metricsql.MetricExpr)
|
metricExpr, ok := expr.(*metricsql.MetricExpr)
|
||||||
if !ok {
|
if !ok || len(metricExpr.LabelFilterss) != 1 {
|
||||||
return fmt.Errorf("failed to parse series %s to metric expr: %v", data.Series, err)
|
return res, fmt.Errorf("got invalid input series %s: %v", data.Series, err)
|
||||||
}
|
}
|
||||||
samples := make([]testutil.Sample, 0, len(promvals))
|
samples := make([]testutil.Sample, 0, len(promvals))
|
||||||
ts := startStamp
|
ts := startStamp
|
||||||
|
@ -71,14 +86,9 @@ func writeInputSeries(input []series, interval *promutils.Duration, startStamp t
|
||||||
for _, filter := range metricExpr.LabelFilterss[0] {
|
for _, filter := range metricExpr.LabelFilterss[0] {
|
||||||
ls = append(ls, testutil.Label{Name: filter.Label, Value: filter.Value})
|
ls = append(ls, testutil.Label{Name: filter.Label, Value: filter.Value})
|
||||||
}
|
}
|
||||||
r.Timeseries = append(r.Timeseries, testutil.TimeSeries{Labels: ls, Samples: samples})
|
res = append(res, testutil.TimeSeries{Labels: ls, Samples: samples})
|
||||||
}
|
}
|
||||||
|
return res, nil
|
||||||
data := testutil.Compress(r)
|
|
||||||
// write input series to vm
|
|
||||||
httpWrite(dst, bytes.NewBuffer(data))
|
|
||||||
vmstorage.Storage.DebugFlush()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseInputValue support input like "1", "1+1x1 _ -4 3+20x1", see more examples in test.
|
// parseInputValue support input like "1", "1+1x1 _ -4 3+20x1", see more examples in test.
|
||||||
|
|
|
@ -2,8 +2,10 @@ package unittest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseInputValue_Failure(t *testing.T) {
|
func TestParseInputValue_Failure(t *testing.T) {
|
||||||
|
@ -43,7 +45,7 @@ func TestParseInputValue_Success(t *testing.T) {
|
||||||
if decimal.IsStaleNaN(outputExpected[i].Value) && decimal.IsStaleNaN(output[i].Value) {
|
if decimal.IsStaleNaN(outputExpected[i].Value) && decimal.IsStaleNaN(output[i].Value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Fatalf("unexpeccted Value field in the output\ngot\n%v\nwant\n%v", output, outputExpected)
|
t.Fatalf("unexpected Value field in the output\ngot\n%v\nwant\n%v", output, outputExpected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,3 +66,34 @@ func TestParseInputValue_Success(t *testing.T) {
|
||||||
|
|
||||||
f("1+1x1 _ -4 stale 3+20x1", []sequenceValue{{Value: 1}, {Value: 2}, {Omitted: true}, {Value: -4}, {Value: decimal.StaleNaN}, {Value: 3}, {Value: 23}})
|
f("1+1x1 _ -4 stale 3+20x1", []sequenceValue{{Value: 1}, {Value: 2}, {Omitted: true}, {Value: -4}, {Value: decimal.StaleNaN}, {Value: 3}, {Value: 23}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseInputSeries_Success(t *testing.T) {
|
||||||
|
f := func(input []series) {
|
||||||
|
t.Helper()
|
||||||
|
var interval promutils.Duration
|
||||||
|
_, err := parseInputSeries(input, &interval, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expect to see no error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f([]series{{Series: "test", Values: "1"}})
|
||||||
|
f([]series{{Series: "test{}", Values: "1"}})
|
||||||
|
f([]series{{Series: "test{env=\"prod\",job=\"a\" }", Values: "1"}})
|
||||||
|
f([]series{{Series: "{__name__=\"test\",env=\"prod\",job=\"a\" }", Values: "1"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseInputSeries_Fail(t *testing.T) {
|
||||||
|
f := func(input []series) {
|
||||||
|
t.Helper()
|
||||||
|
var interval promutils.Duration
|
||||||
|
_, err := parseInputSeries(input, &interval, time.Now())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expect to see error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f([]series{{Series: "", Values: "1"}})
|
||||||
|
f([]series{{Series: "{}", Values: "1"}})
|
||||||
|
f([]series{{Series: "{env=\"prod\",job=\"a\" or env=\"dev\",job=\"b\"}", Values: "1"}})
|
||||||
|
}
|
||||||
|
|
|
@ -57,16 +57,18 @@ Outer:
|
||||||
continue Outer
|
continue Outer
|
||||||
}
|
}
|
||||||
metricsqlMetricExpr, ok := metricsqlExpr.(*metricsql.MetricExpr)
|
metricsqlMetricExpr, ok := metricsqlExpr.(*metricsql.MetricExpr)
|
||||||
if !ok {
|
if !ok || len(metricsqlMetricExpr.LabelFilterss) > 1 {
|
||||||
checkErrs = append(checkErrs, fmt.Errorf("\n expr: %q, time: %s, err: %v", mt.Expr,
|
checkErrs = append(checkErrs, fmt.Errorf("\n expr: %q, time: %s, err: %v", mt.Expr,
|
||||||
mt.EvalTime.Duration().String(), fmt.Errorf("got unsupported metricsql type")))
|
mt.EvalTime.Duration().String(), fmt.Errorf("got invalid exp_samples: %q", s.Labels)))
|
||||||
continue Outer
|
continue Outer
|
||||||
}
|
}
|
||||||
for _, l := range metricsqlMetricExpr.LabelFilterss[0] {
|
if len(metricsqlMetricExpr.LabelFilterss) > 0 {
|
||||||
expLb = append(expLb, datasource.Label{
|
for _, l := range metricsqlMetricExpr.LabelFilterss[0] {
|
||||||
Name: l.Label,
|
expLb = append(expLb, datasource.Label{
|
||||||
Value: l.Value,
|
Name: l.Label,
|
||||||
})
|
Value: l.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Slice(expLb, func(i, j int) bool {
|
sort.Slice(expLb, func(i, j int) bool {
|
||||||
|
|
|
@ -30,6 +30,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix error messages rendering from overflowing the screen with long messages. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7207).
|
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): fix error messages rendering from overflowing the screen with long messages. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7207).
|
||||||
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): properly add metrics tags for `opentsdb` migration source. Previously it could have empty values. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7161).
|
* BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): properly add metrics tags for `opentsdb` migration source. Previously it could have empty values. See [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7161).
|
||||||
* BUGFIX: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): reduce the initial health check interval for datasource. This reduces the time spent on evaluating rules by vmalert-tool. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6970).
|
* BUGFIX: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): reduce the initial health check interval for datasource. This reduces the time spent on evaluating rules by vmalert-tool. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6970).
|
||||||
|
* BUGFIX: [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/): allow specifying empty labels list `labels: '{}'` in the same way as promtool does. This improves compatibility between these tools.
|
||||||
|
|
||||||
## [v1.104.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.104.0)
|
## [v1.104.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.104.0)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue