Skip to content

Commit 6d3700e

Browse files
authored
Merge pull request #7056 from SungJin1212/Add-changelog-for-utf8-support
2 parents c884d66 + 0f8f7fa commit 6d3700e

File tree

17 files changed

+297
-126
lines changed

17 files changed

+297
-126
lines changed

.github/workflows/test-build-deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ jobs:
213213
docker pull quay.io/cortexproject/cortex:v1.18.1
214214
elif [ "$TEST_TAGS" = "integration_query_fuzz" ]; then
215215
docker pull quay.io/cortexproject/cortex:v1.18.1
216-
docker pull quay.io/prometheus/prometheus:v3.5.0
216+
docker pull quay.io/prometheus/prometheus:v3.6.0
217217
fi
218218
docker pull memcached:1.6.1
219219
docker pull redis:7.0.4-alpine

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* [FEATURE] Querier: Support for configuring query optimizers and enabling XFunctions in the Thanos engine. #6873
2525
* [FEATURE] Query Frontend: Add support /api/v1/format_query API for formatting queries. #6893
2626
* [FEATURE] Query Frontend: Add support for /api/v1/parse_query API (experimental) to parse a PromQL expression and return it as a JSON-formatted AST (abstract syntax tree). #6978
27+
* [ENHANCEMENT] Upgrade the Prometheus version to 3.6.0 and add a `-name-validation-scheme` flag to support UTF-8. #7040 #7056
2728
* [ENHANCEMENT] Distributor: Emit an error with a 400 status code when empty labels are found before the relabelling or label dropping process. #7052
2829
* [ENHANCEMENT] Parquet Storage: Add support for additional sort columns during Parquet file generation #7003
2930
* [ENHANCEMENT] Modernizes the entire codebase by using go modernize tool. #7005

docs/configuration/config-file-reference.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ Where default_value is the value to use if the environment variable is undefined
6868
# CLI flag: -http.prefix
6969
[http_prefix: <string> | default = "/api/prom"]
7070

71+
# Name validation scheme for metric names and label names, Support values are:
72+
# legacy, utf8.
73+
# CLI flag: -name-validation-scheme
74+
[name_validation_scheme: <int> | default = legacy]
75+
7176
resource_monitor:
7277
# Comma-separated list of resources to monitor. Supported values are cpu and
7378
# heap, which tracks metrics from github.com/prometheus/procfs and
@@ -4344,11 +4349,6 @@ query_rejection:
43444349

43454350
# list of rule groups to disable
43464351
[disabled_rule_groups: <list of DisabledRuleGroup> | default = []]
4347-
4348-
# Name validation scheme for metric names and label names, Support values are:
4349-
# legacy, utf8.
4350-
# CLI flag: -validation.name-validation-scheme
4351-
[name_validation_scheme: <int> | default = legacy]
43524352
```
43534353
43544354
### `memberlist_config`

integration/e2e/images/images.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ var (
1111
Minio = "minio/minio:RELEASE.2024-05-28T17-19-04Z"
1212
Consul = "consul:1.8.4"
1313
ETCD = "gcr.io/etcd-development/etcd:v3.4.7"
14-
Prometheus = "quay.io/prometheus/prometheus:v3.5.0"
14+
Prometheus = "quay.io/prometheus/prometheus:v3.6.0"
1515
)

integration/utf8_test.go

Lines changed: 179 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
package integration
55

66
import (
7+
"context"
78
"fmt"
89
"path/filepath"
910
"testing"
1011
"time"
1112

13+
amlabels "github.com/prometheus/alertmanager/pkg/labels"
14+
"github.com/prometheus/alertmanager/types"
15+
"github.com/prometheus/common/model"
16+
"github.com/prometheus/prometheus/model/labels"
17+
"github.com/prometheus/prometheus/model/rulefmt"
1218
"github.com/prometheus/prometheus/prompb"
1319
"github.com/stretchr/testify/require"
1420

@@ -17,52 +23,156 @@ import (
1723
"github.com/cortexproject/cortex/integration/e2ecortex"
1824
)
1925

20-
func Test_RulerExternalLabels_UTF8Validation(t *testing.T) {
26+
const utf8AlertmanagerConfig = `route:
27+
receiver: dummy
28+
group_by: [group.test.🙂]
29+
routes:
30+
- matchers:
31+
- foo.🙂=bar.🙂
32+
receivers:
33+
- name: dummy`
34+
35+
func Test_Alertmanager_UTF8(t *testing.T) {
2136
s, err := e2e.NewScenario(networkName)
2237
require.NoError(t, err)
2338
defer s.Close()
2439

25-
// Start dependencies.
26-
minio := e2edb.NewMinio(9000, bucketName)
40+
flags := mergeFlags(AlertmanagerFlags(), AlertmanagerS3Flags(),
41+
map[string]string{
42+
"-name-validation-scheme": "utf8",
43+
},
44+
)
45+
46+
minio := e2edb.NewMinio(9000, alertsBucketName)
2747
require.NoError(t, s.StartAndWaitReady(minio))
2848

49+
alertmanager := e2ecortex.NewAlertmanager(
50+
"alertmanager",
51+
flags,
52+
"",
53+
)
54+
55+
require.NoError(t, s.StartAndWaitReady(alertmanager))
56+
57+
c, err := e2ecortex.NewClient("", "", alertmanager.HTTPEndpoint(), "", "user-1")
58+
require.NoError(t, err)
59+
60+
ctx := context.Background()
61+
62+
err = c.SetAlertmanagerConfig(ctx, utf8AlertmanagerConfig, map[string]string{})
63+
require.NoError(t, err)
64+
65+
require.NoError(t, alertmanager.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_alertmanager_config_last_reload_successful"}, e2e.WaitMissingMetrics))
66+
require.NoError(t, alertmanager.WaitSumMetricsWithOptions(e2e.Greater(0), []string{"cortex_alertmanager_config_hash"}, e2e.WaitMissingMetrics))
67+
68+
silenceId, err := c.CreateSilence(ctx, types.Silence{
69+
Matchers: amlabels.Matchers{
70+
{Name: "silences.name.🙂", Value: "silences.value.🙂"},
71+
},
72+
Comment: "test silences",
73+
StartsAt: time.Now(),
74+
EndsAt: time.Now().Add(time.Minute),
75+
})
76+
require.NoError(t, err)
77+
require.NotEmpty(t, silenceId)
78+
require.NoError(t, alertmanager.WaitSumMetrics(e2e.Equals(1), "cortex_alertmanager_silences"))
79+
80+
err = c.SendAlertToAlermanager(ctx, &model.Alert{
81+
Labels: model.LabelSet{
82+
"alert.name.🙂": "alert.value.🙂",
83+
},
84+
StartsAt: time.Now(),
85+
EndsAt: time.Now().Add(time.Minute),
86+
})
87+
require.NoError(t, err)
88+
require.NoError(t, alertmanager.WaitSumMetrics(e2e.Equals(1), "cortex_alertmanager_alerts_received_total"))
89+
}
90+
91+
func Test_Ruler_UTF8(t *testing.T) {
92+
s, err := e2e.NewScenario(networkName)
93+
require.NoError(t, err)
94+
defer s.Close()
95+
96+
// Start dependencies.
97+
consul := e2edb.NewConsul()
98+
minio := e2edb.NewMinio(9000, rulestoreBucketName, bucketName)
99+
require.NoError(t, s.StartAndWaitReady(consul, minio))
100+
29101
runtimeConfigYamlFile := `
30102
overrides:
31-
'user-2':
32-
name_validation_scheme: utf8
103+
'user-1':
33104
ruler_external_labels:
34105
test.utf8.metric: 😄
35106
`
36107
require.NoError(t, writeFileToSharedDir(s, runtimeConfigFile, []byte(runtimeConfigYamlFile)))
37108
filePath := filepath.Join(e2e.ContainerSharedDir, runtimeConfigFile)
38109

39-
// Start Cortex components.
40-
require.NoError(t, copyFileToSharedDir(s, "docs/configuration/single-process-config-blocks.yaml", cortexConfigFile))
110+
flags := mergeFlags(
111+
BlocksStorageFlags(),
112+
RulerFlags(),
113+
map[string]string{
114+
"-runtime-config.file": filePath,
115+
"-runtime-config.backend": "filesystem",
116+
"-name-validation-scheme": "utf8",
41117

42-
flags := map[string]string{
43-
"-auth.enabled": "true",
44-
"-runtime-config.file": filePath,
45-
"-runtime-config.backend": "filesystem",
46-
// ingester
47-
"-blocks-storage.s3.access-key-id": e2edb.MinioAccessKey,
48-
"-blocks-storage.s3.secret-access-key": e2edb.MinioSecretKey,
49-
"-blocks-storage.s3.bucket-name": bucketName,
50-
"-blocks-storage.s3.endpoint": fmt.Sprintf("%s-minio-9000:9000", networkName),
51-
"-blocks-storage.s3.insecure": "true",
52-
// alert manager
53-
"-alertmanager.web.external-url": "http://localhost/alertmanager",
54-
"-alertmanager-storage.backend": "local",
55-
"-alertmanager-storage.local.path": filepath.Join(e2e.ContainerSharedDir, "alertmanager_configs"),
56-
}
118+
"-ring.store": "consul",
119+
"-consul.hostname": consul.NetworkHTTPEndpoint(),
120+
// ingester
121+
"-blocks-storage.s3.access-key-id": e2edb.MinioAccessKey,
122+
"-blocks-storage.s3.secret-access-key": e2edb.MinioSecretKey,
123+
"-blocks-storage.s3.bucket-name": bucketName,
124+
"-blocks-storage.s3.endpoint": fmt.Sprintf("%s-minio-9000:9000", networkName),
125+
"-blocks-storage.s3.insecure": "true",
126+
// alert manager
127+
"-alertmanager.web.external-url": "http://localhost/alertmanager",
128+
"-alertmanager-storage.backend": "local",
129+
"-alertmanager-storage.local.path": filepath.Join(e2e.ContainerSharedDir, "alertmanager_configs"),
130+
},
131+
)
57132
// make alert manager config dir
58133
require.NoError(t, writeFileToSharedDir(s, "alertmanager_configs", []byte{}))
59134

60-
// The external labels validation should be success
61-
cortex := e2ecortex.NewSingleBinaryWithConfigFile("cortex-1", cortexConfigFile, flags, "", 9009, 9095)
135+
// Start Cortex.
136+
cortex := e2ecortex.NewSingleBinary("cortex", flags, "")
62137
require.NoError(t, s.StartAndWaitReady(cortex))
138+
139+
groupLabels := map[string]string{
140+
"group.label.😄": "group.value",
141+
}
142+
ruleLabels := map[string]string{
143+
"rule.label.😄": "rule.value",
144+
}
145+
146+
interval, _ := model.ParseDuration("1s")
147+
148+
ruleGroup := rulefmt.RuleGroup{
149+
Name: "rule.utf8.😄",
150+
Interval: interval,
151+
Rules: []rulefmt.Rule{{
152+
Alert: "alert.rule.😄",
153+
Expr: "up",
154+
Labels: ruleLabels,
155+
}, {
156+
Record: "record.rule.😄",
157+
Expr: "up",
158+
Labels: ruleLabels,
159+
}},
160+
Labels: groupLabels,
161+
}
162+
163+
c, err := e2ecortex.NewClient("", "", "", cortex.HTTPEndpoint(), "user-1")
164+
require.NoError(t, err)
165+
166+
err = c.SetRuleGroup(ruleGroup, "namespace")
167+
require.NoError(t, err)
168+
require.NoError(t, cortex.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_ruler_managers_total"}), e2e.WithLabelMatchers(labels.MustNewMatcher(labels.MatchEqual, "user", "user-1")))
169+
require.NoError(t, cortex.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_ruler_rule_groups_in_store"}, e2e.WithLabelMatchers(
170+
labels.MustNewMatcher(labels.MatchEqual, "user", "user-1")),
171+
e2e.WaitMissingMetrics,
172+
))
63173
}
64174

65-
func Test_Distributor_UTF8ValidationPerTenant(t *testing.T) {
175+
func Test_PushQuery_UTF8(t *testing.T) {
66176
s, err := e2e.NewScenario(networkName)
67177
require.NoError(t, err)
68178
defer s.Close()
@@ -71,22 +181,12 @@ func Test_Distributor_UTF8ValidationPerTenant(t *testing.T) {
71181
minio := e2edb.NewMinio(9000, bucketName)
72182
require.NoError(t, s.StartAndWaitReady(minio))
73183

74-
runtimeConfigYamlFile := `
75-
overrides:
76-
'user-2':
77-
name_validation_scheme: utf8
78-
`
79-
80-
require.NoError(t, writeFileToSharedDir(s, runtimeConfigFile, []byte(runtimeConfigYamlFile)))
81-
filePath := filepath.Join(e2e.ContainerSharedDir, runtimeConfigFile)
82-
83184
// Start Cortex components.
84185
require.NoError(t, copyFileToSharedDir(s, "docs/configuration/single-process-config-blocks.yaml", cortexConfigFile))
85186

86187
flags := map[string]string{
87188
"-auth.enabled": "true",
88-
"-runtime-config.file": filePath,
89-
"-runtime-config.backend": "filesystem",
189+
"-name-validation-scheme": "utf8",
90190
// ingester
91191
"-blocks-storage.s3.access-key-id": e2edb.MinioAccessKey,
92192
"-blocks-storage.s3.secret-access-key": e2edb.MinioSecretKey,
@@ -104,34 +204,62 @@ overrides:
104204
cortex := e2ecortex.NewSingleBinaryWithConfigFile("cortex-1", cortexConfigFile, flags, "", 9009, 9095)
105205
require.NoError(t, s.StartAndWaitReady(cortex))
106206

107-
// user-1 uses legacy validation
108-
user1Client, err := e2ecortex.NewClient(cortex.HTTPEndpoint(), "", "", "", "user-1")
109-
require.NoError(t, err)
110-
111-
// user-2 uses utf8 validation
112-
user2Client, err := e2ecortex.NewClient(cortex.HTTPEndpoint(), "", "", "", "user-2")
207+
c, err := e2ecortex.NewClient(cortex.HTTPEndpoint(), cortex.HTTPEndpoint(), "", "", "user-1")
113208
require.NoError(t, err)
114209

115210
now := time.Now()
116211

117-
utf8Series, _ := generateSeries("series_1", now, prompb.Label{Name: "test.utf8.metric", Value: "😄"})
212+
utf8Series, _ := generateSeries("series.1", now, prompb.Label{Name: "test.utf8.metric", Value: "😄"})
118213
legacySeries, _ := generateSeries("series_2", now, prompb.Label{Name: "job", Value: "test"})
119214

120-
res, err := user1Client.Push(legacySeries)
215+
metadata := []prompb.MetricMetadata{
216+
{
217+
MetricFamilyName: "metadata.name",
218+
Help: "metadata.help",
219+
Unit: "metadata.unit",
220+
},
221+
}
222+
223+
res, err := c.Push(legacySeries, metadata...)
121224
require.NoError(t, err)
122225
require.Equal(t, 200, res.StatusCode)
123226

124-
// utf8Series push should be fail for user-1
125-
res, err = user1Client.Push(utf8Series)
227+
// utf8Series push should be success
228+
res, err = c.Push(utf8Series)
126229
require.NoError(t, err)
127-
require.Equal(t, 400, res.StatusCode)
230+
require.Equal(t, 200, res.StatusCode)
128231

129-
res, err = user2Client.Push(legacySeries)
232+
// utf8 querying
233+
// c.f. https://prometheus.io/docs/guides/utf8/#querying
234+
query := `{"series.1", "test.utf8.metric"="😄"}`
235+
queryResult, err := c.Query(query, now)
130236
require.NoError(t, err)
131237
require.Equal(t, 200, res.StatusCode)
238+
require.Equal(t, model.ValVector, queryResult.Type())
239+
vec := queryResult.(model.Vector)
240+
require.Equal(t, 1, len(vec))
132241

133-
// utf8Series push should be success for user-2
134-
res, err = user2Client.Push(utf8Series)
242+
// label names
243+
start := now
244+
end := now.Add(time.Minute * 5)
245+
labelNames, err := c.LabelNames(start, end)
135246
require.NoError(t, err)
136-
require.Equal(t, 200, res.StatusCode)
247+
require.Equal(t, []string{"__name__", "job", "test.utf8.metric"}, labelNames)
248+
249+
// series
250+
series, err := c.Series([]string{`{"test.utf8.metric"="😄"}`}, start, end)
251+
require.NoError(t, err)
252+
require.Equal(t, 1, len(series))
253+
require.Equal(t, `{__name__="series.1", test.utf8.metric="😄"}`, series[0].String())
254+
255+
// label values
256+
labelValues, err := c.LabelValues("test.utf8.metric", start, end, nil)
257+
require.NoError(t, err)
258+
require.Equal(t, 1, len(labelValues))
259+
require.Equal(t, model.LabelValue("😄"), labelValues[0])
260+
261+
// metadata
262+
metadataResult, err := c.Metadata("metadata.name", "")
263+
require.NoError(t, err)
264+
require.Equal(t, 1, len(metadataResult))
137265
}

pkg/cortex/configinit/init.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)