mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmselect/promql: add label_uppercase(q, label1, ... labelN)
and label_lowercase(q, label1, ... labelN)
functions
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/936
This commit is contained in:
parent
d0e1589ea9
commit
66379cc69f
9 changed files with 107 additions and 5 deletions
|
@ -1090,6 +1090,62 @@ func TestExecSuccess(t *testing.T) {
|
||||||
resultExpected := []netstorage.Result{r1, r2, r3, r4, r5}
|
resultExpected := []netstorage.Result{r1, r2, r3, r4, r5}
|
||||||
f(q, resultExpected)
|
f(q, resultExpected)
|
||||||
})
|
})
|
||||||
|
t.Run(`label_uppercase`, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
q := `label_uppercase(
|
||||||
|
label_set(time(), "foo", "bAr", "XXx", "yyy", "zzz", "abc"),
|
||||||
|
"foo", "XXx", "aaa"
|
||||||
|
)`
|
||||||
|
r := netstorage.Result{
|
||||||
|
MetricName: metricNameExpected,
|
||||||
|
Values: []float64{1000, 1200, 1400, 1600, 1800, 2000},
|
||||||
|
Timestamps: timestampsExpected,
|
||||||
|
}
|
||||||
|
r.MetricName.Tags = []storage.Tag{
|
||||||
|
{
|
||||||
|
Key: []byte("XXx"),
|
||||||
|
Value: []byte("YYY"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: []byte("foo"),
|
||||||
|
Value: []byte("BAR"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: []byte("zzz"),
|
||||||
|
Value: []byte("abc"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resultExpected := []netstorage.Result{r}
|
||||||
|
f(q, resultExpected)
|
||||||
|
})
|
||||||
|
t.Run(`label_lowercase`, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
q := `label_lowercase(
|
||||||
|
label_set(time(), "foo", "bAr", "XXx", "yyy", "zzz", "aBc"),
|
||||||
|
"foo", "XXx", "aaa"
|
||||||
|
)`
|
||||||
|
r := netstorage.Result{
|
||||||
|
MetricName: metricNameExpected,
|
||||||
|
Values: []float64{1000, 1200, 1400, 1600, 1800, 2000},
|
||||||
|
Timestamps: timestampsExpected,
|
||||||
|
}
|
||||||
|
r.MetricName.Tags = []storage.Tag{
|
||||||
|
{
|
||||||
|
Key: []byte("XXx"),
|
||||||
|
Value: []byte("yyy"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: []byte("foo"),
|
||||||
|
Value: []byte("bar"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: []byte("zzz"),
|
||||||
|
Value: []byte("aBc"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resultExpected := []netstorage.Result{r}
|
||||||
|
f(q, resultExpected)
|
||||||
|
})
|
||||||
t.Run(`label_copy(new_tag)`, func(t *testing.T) {
|
t.Run(`label_copy(new_tag)`, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
q := `label_copy(
|
q := `label_copy(
|
||||||
|
@ -6217,6 +6273,8 @@ func TestExecError(t *testing.T) {
|
||||||
f(`label_transform(1, "foo", "invalid(regexp", "baz`)
|
f(`label_transform(1, "foo", "invalid(regexp", "baz`)
|
||||||
f(`label_match(1, 2, 3)`)
|
f(`label_match(1, 2, 3)`)
|
||||||
f(`label_mismatch(1, 2, 3)`)
|
f(`label_mismatch(1, 2, 3)`)
|
||||||
|
f(`label_uppercase()`)
|
||||||
|
f(`label_lowercase()`)
|
||||||
f(`alias(1, 2)`)
|
f(`alias(1, 2)`)
|
||||||
f(`aggr_over_time(1, 2)`)
|
f(`aggr_over_time(1, 2)`)
|
||||||
f(`aggr_over_time(("foo", "bar"), 3)`)
|
f(`aggr_over_time(("foo", "bar"), 3)`)
|
||||||
|
|
|
@ -73,6 +73,8 @@ var transformFuncs = map[string]transformFunc{
|
||||||
// New funcs
|
// New funcs
|
||||||
"label_set": transformLabelSet,
|
"label_set": transformLabelSet,
|
||||||
"label_map": transformLabelMap,
|
"label_map": transformLabelMap,
|
||||||
|
"label_uppercase": transformLabelUppercase,
|
||||||
|
"label_lowercase": transformLabelLowercase,
|
||||||
"label_del": transformLabelDel,
|
"label_del": transformLabelDel,
|
||||||
"label_keep": transformLabelKeep,
|
"label_keep": transformLabelKeep,
|
||||||
"label_copy": transformLabelCopy,
|
"label_copy": transformLabelCopy,
|
||||||
|
@ -1196,6 +1198,42 @@ func transformLabelSet(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||||
return rvs, nil
|
return rvs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transformLabelUppercase(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||||
|
return transformLabelValueFunc(tfa, strings.ToUpper)
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformLabelLowercase(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||||
|
return transformLabelValueFunc(tfa, strings.ToLower)
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformLabelValueFunc(tfa *transformFuncArg, f func(string) string) ([]*timeseries, error) {
|
||||||
|
args := tfa.args
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, fmt.Errorf(`not enough args; got %d; want at least %d`, len(args), 2)
|
||||||
|
}
|
||||||
|
labels := make([]string, 0, len(args)-1)
|
||||||
|
for i := 1; i < len(args); i++ {
|
||||||
|
label, err := getString(args[i], i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
labels = append(labels, label)
|
||||||
|
}
|
||||||
|
|
||||||
|
rvs := args[0]
|
||||||
|
for _, ts := range rvs {
|
||||||
|
mn := &ts.MetricName
|
||||||
|
for _, label := range labels {
|
||||||
|
dstValue := getDstValue(mn, label)
|
||||||
|
*dstValue = append((*dstValue)[:0], f(string(*dstValue))...)
|
||||||
|
if len(*dstValue) == 0 {
|
||||||
|
mn.RemoveTag(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rvs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func transformLabelMap(tfa *transformFuncArg) ([]*timeseries, error) {
|
func transformLabelMap(tfa *transformFuncArg) ([]*timeseries, error) {
|
||||||
args := tfa.args
|
args := tfa.args
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# tip
|
# tip
|
||||||
|
|
||||||
* FEATURE: optimize Consul service discovery speed when discovering big number of services. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/574
|
* FEATURE: optimize Consul service discovery speed when discovering big number of services. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/574
|
||||||
|
* FEATURE: add `label_uppercase(q, label1, ... labelN)` and `label_lowercase(q, label1, ... labelN)` function to [MetricsQL](https://victoriametrics.github.io/MetricsQL.html)
|
||||||
|
for uppercasing and lowercasing values for the given labels. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/936
|
||||||
|
|
||||||
* BUGFIX: properly parse timestamps in OpenMetrics format - they are exposed as floating-point number in seconds instead of integer milliseconds
|
* BUGFIX: properly parse timestamps in OpenMetrics format - they are exposed as floating-point number in seconds instead of integer milliseconds
|
||||||
unlike in Prometheus exposition format. See [the docs](https://github.com/OpenObservability/OpenMetrics/blob/master/specification/OpenMetrics.md#timestamps).
|
unlike in Prometheus exposition format. See [the docs](https://github.com/OpenObservability/OpenMetrics/blob/master/specification/OpenMetrics.md#timestamps).
|
||||||
|
|
|
@ -57,6 +57,8 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g
|
||||||
- `alias(q, name)` for setting metric name across all the time series `q`.
|
- `alias(q, name)` for setting metric name across all the time series `q`.
|
||||||
- `label_set(q, label1, value1, ... labelN, valueN)` for setting the given values for the given labels on `q`.
|
- `label_set(q, label1, value1, ... labelN, valueN)` for setting the given values for the given labels on `q`.
|
||||||
- `label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN)` for mapping `label` values from `src*` to `dst*`.
|
- `label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN)` for mapping `label` values from `src*` to `dst*`.
|
||||||
|
- `label_uppercase(q, label1, ... labelN)` for uppercasing values for the given labels.
|
||||||
|
- `label_lowercase(q, label2, ... labelN)` for lowercasing value for the given labels.
|
||||||
- `label_del(q, label1, ... labelN)` for deleting the given labels from `q`.
|
- `label_del(q, label1, ... labelN)` for deleting the given labels from `q`.
|
||||||
- `label_keep(q, label1, ... labelN)` for deleting all the labels except the given labels from `q`.
|
- `label_keep(q, label1, ... labelN)` for deleting all the labels except the given labels from `q`.
|
||||||
- `label_copy(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for copying label values from `src_*` to `dst_*`.
|
- `label_copy(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for copying label values from `src_*` to `dst_*`.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -8,7 +8,7 @@ require (
|
||||||
// like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b
|
// like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b
|
||||||
github.com/VictoriaMetrics/fasthttp v1.0.9
|
github.com/VictoriaMetrics/fasthttp v1.0.9
|
||||||
github.com/VictoriaMetrics/metrics v1.12.3
|
github.com/VictoriaMetrics/metrics v1.12.3
|
||||||
github.com/VictoriaMetrics/metricsql v0.7.3
|
github.com/VictoriaMetrics/metricsql v0.8.0
|
||||||
github.com/aws/aws-sdk-go v1.36.0
|
github.com/aws/aws-sdk-go v1.36.0
|
||||||
github.com/cespare/xxhash/v2 v2.1.1
|
github.com/cespare/xxhash/v2 v2.1.1
|
||||||
github.com/golang/snappy v0.0.2
|
github.com/golang/snappy v0.0.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -45,8 +45,8 @@ github.com/VictoriaMetrics/fasthttp v1.0.9/go.mod h1:3SeUL4zwB/p/a9aEeRc6gdlbrtN
|
||||||
github.com/VictoriaMetrics/metrics v1.12.2/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
|
github.com/VictoriaMetrics/metrics v1.12.2/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
|
||||||
github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I=
|
github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I=
|
||||||
github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
|
github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
|
||||||
github.com/VictoriaMetrics/metricsql v0.7.3 h1:ReI+UBleCkGMmYDt69gsuGld71l1WpQDIlhgU1N5xQ8=
|
github.com/VictoriaMetrics/metricsql v0.8.0 h1:fUZWNjXYJhiCKoEXr86pM4RaAxfA3SqkAhJLe1gr/mo=
|
||||||
github.com/VictoriaMetrics/metricsql v0.7.3/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
|
github.com/VictoriaMetrics/metricsql v0.8.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
|
|
2
vendor/github.com/VictoriaMetrics/metricsql/optimizer.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/metricsql/optimizer.go
generated
vendored
|
@ -110,7 +110,7 @@ func getMetricExprForOptimization(e Expr) *MetricExpr {
|
||||||
if IsTransformFunc(fe.Name) {
|
if IsTransformFunc(fe.Name) {
|
||||||
switch strings.ToLower(fe.Name) {
|
switch strings.ToLower(fe.Name) {
|
||||||
case "absent", "histogram_quantile", "label_join", "label_replace", "scalar", "vector",
|
case "absent", "histogram_quantile", "label_join", "label_replace", "scalar", "vector",
|
||||||
"label_set", "label_map", "label_del", "label_keep", "label_copy",
|
"label_set", "label_map", "label_uppercase", "label_lowercase", "label_del", "label_keep", "label_copy",
|
||||||
"label_move", "label_transform", "label_value", "label_match", "label_mismatch",
|
"label_move", "label_transform", "label_value", "label_match", "label_mismatch",
|
||||||
"prometheus_buckets", "buckets_limit", "histogram_share", "union", "":
|
"prometheus_buckets", "buckets_limit", "histogram_share", "union", "":
|
||||||
// metric expressions for these functions cannot be optimized.
|
// metric expressions for these functions cannot be optimized.
|
||||||
|
|
2
vendor/github.com/VictoriaMetrics/metricsql/transform.go
generated
vendored
2
vendor/github.com/VictoriaMetrics/metricsql/transform.go
generated
vendored
|
@ -39,6 +39,8 @@ var transformFuncs = map[string]bool{
|
||||||
// New funcs from MetricsQL
|
// New funcs from MetricsQL
|
||||||
"label_set": true,
|
"label_set": true,
|
||||||
"label_map": true,
|
"label_map": true,
|
||||||
|
"label_uppercase": true,
|
||||||
|
"label_lowercase": true,
|
||||||
"label_del": true,
|
"label_del": true,
|
||||||
"label_keep": true,
|
"label_keep": true,
|
||||||
"label_copy": true,
|
"label_copy": true,
|
||||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -16,7 +16,7 @@ github.com/VictoriaMetrics/fasthttp/fasthttputil
|
||||||
github.com/VictoriaMetrics/fasthttp/stackless
|
github.com/VictoriaMetrics/fasthttp/stackless
|
||||||
# github.com/VictoriaMetrics/metrics v1.12.3
|
# github.com/VictoriaMetrics/metrics v1.12.3
|
||||||
github.com/VictoriaMetrics/metrics
|
github.com/VictoriaMetrics/metrics
|
||||||
# github.com/VictoriaMetrics/metricsql v0.7.3
|
# github.com/VictoriaMetrics/metricsql v0.8.0
|
||||||
github.com/VictoriaMetrics/metricsql
|
github.com/VictoriaMetrics/metricsql
|
||||||
github.com/VictoriaMetrics/metricsql/binaryop
|
github.com/VictoriaMetrics/metricsql/binaryop
|
||||||
# github.com/aws/aws-sdk-go v1.36.0
|
# github.com/aws/aws-sdk-go v1.36.0
|
||||||
|
|
Loading…
Reference in a new issue