-
Notifications
You must be signed in to change notification settings - Fork 674
LabelNames API with matchers #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
86e6e55
8b2a36b
5329ae5
8793512
9e32615
99aa870
a31b302
2342f8d
c74a9b1
d476d30
f241e5e
bd8492b
893228a
5a7ea80
f9f5518
ce8a310
4025689
01e894d
6b451eb
79ab2db
28aa6a8
0e3681d
2809837
70d23fd
20597a8
8f51e15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1808,6 +1808,115 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| func TestDistributor_LabelNames(t *testing.T) { | ||
| const numIngesters = 5 | ||
|
|
||
| fixtures := []struct { | ||
| lbls labels.Labels | ||
| value float64 | ||
| timestamp int64 | ||
| }{ | ||
| {labels.Labels{{Name: labels.MetricName, Value: "test_1"}, {Name: "status", Value: "200"}}, 1, 100000}, | ||
| {labels.Labels{{Name: labels.MetricName, Value: "test_1"}, {Name: "status", Value: "500"}}, 1, 110000}, | ||
| {labels.Labels{{Name: labels.MetricName, Value: "test_2"}}, 2, 200000}, | ||
| // The two following series have the same FastFingerprint=e002a3a451262627 | ||
| {labels.Labels{{Name: labels.MetricName, Value: "fast_fingerprint_collision"}, {Name: "app", Value: "l"}, {Name: "uniq0", Value: "0"}, {Name: "uniq1", Value: "1"}}, 1, 300000}, | ||
| {labels.Labels{{Name: labels.MetricName, Value: "fast_fingerprint_collision"}, {Name: "app", Value: "m"}, {Name: "uniq0", Value: "1"}, {Name: "uniq1", Value: "1"}}, 1, 300000}, | ||
| } | ||
|
|
||
| tests := map[string]struct { | ||
| shuffleShardEnabled bool | ||
| shuffleShardSize int | ||
| matchers []*labels.Matcher | ||
| expectedResult []string | ||
| expectedIngesters int | ||
| }{ | ||
| "should return an empty response if no metric match": { | ||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "unknown"), | ||
| }, | ||
| expectedResult: []string{}, | ||
| expectedIngesters: numIngesters, | ||
| }, | ||
| "should filter metrics by single matcher": { | ||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"), | ||
| }, | ||
| expectedResult: []string{labels.MetricName, "status"}, | ||
| expectedIngesters: numIngesters, | ||
| }, | ||
| "should filter metrics by multiple matchers": { | ||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, "status", "200"), | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"), | ||
| }, | ||
| expectedResult: []string{labels.MetricName, "status"}, | ||
colega marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| expectedIngesters: numIngesters, | ||
| }, | ||
| "should return all matching metrics even if their FastFingerprint collide": { | ||
|
||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "fast_fingerprint_collision"), | ||
| }, | ||
| expectedResult: []string{labels.MetricName, "app", "uniq0", "uniq1"}, | ||
| expectedIngesters: numIngesters, | ||
| }, | ||
| "should query only ingesters belonging to tenant's subring if shuffle sharding is enabled": { | ||
| shuffleShardEnabled: true, | ||
| shuffleShardSize: 3, | ||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"), | ||
| }, | ||
| expectedResult: []string{labels.MetricName, "status"}, | ||
| expectedIngesters: 3, | ||
| }, | ||
| "should query all ingesters if shuffle sharding is enabled but shard size is 0": { | ||
| shuffleShardEnabled: true, | ||
| shuffleShardSize: 0, | ||
| matchers: []*labels.Matcher{ | ||
| mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"), | ||
| }, | ||
| expectedResult: []string{labels.MetricName, "status"}, | ||
| expectedIngesters: numIngesters, | ||
| }, | ||
| } | ||
|
|
||
| for testName, testData := range tests { | ||
| t.Run(testName, func(t *testing.T) { | ||
| now := model.Now() | ||
|
|
||
| // Create distributor | ||
| ds, ingesters, r, _ := prepare(t, prepConfig{ | ||
| numIngesters: numIngesters, | ||
| happyIngesters: numIngesters, | ||
| numDistributors: 1, | ||
| shardByAllLabels: true, | ||
| shuffleShardEnabled: testData.shuffleShardEnabled, | ||
| shuffleShardSize: testData.shuffleShardSize, | ||
| }) | ||
| defer stopAll(ds, r) | ||
|
|
||
| // Push fixtures | ||
| ctx := user.InjectOrgID(context.Background(), "test") | ||
|
|
||
| for _, series := range fixtures { | ||
| req := mockWriteRequest(series.lbls, series.value, series.timestamp) | ||
| _, err := ds[0].Push(ctx, req) | ||
| require.NoError(t, err) | ||
| } | ||
|
|
||
| names, err := ds[0].LabelNames(ctx, now, now, testData.matchers...) | ||
| require.NoError(t, err) | ||
| assert.ElementsMatch(t, testData.expectedResult, names) | ||
|
|
||
| // Check how many ingesters have been queried. | ||
| // Due to the quorum the distributor could cancel the last request towards ingesters | ||
| // if all other ones are successful, so we're good either has been queried X or X-1 | ||
| // ingesters. | ||
| assert.Contains(t, []int{testData.expectedIngesters, testData.expectedIngesters - 1}, countMockIngestersCalls(ingesters, "LabelNames")) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDistributor_MetricsMetadata(t *testing.T) { | ||
| const numIngesters = 5 | ||
|
|
||
|
|
@@ -2346,6 +2455,34 @@ func (i *mockIngester) MetricsForLabelMatchers(ctx context.Context, req *client. | |
| return &response, nil | ||
| } | ||
|
|
||
| func (i *mockIngester) LabelNames(ctx context.Context, req *client.LabelNamesRequest, opts ...grpc.CallOption) (*client.LabelNamesResponse, error) { | ||
| i.Lock() | ||
| defer i.Unlock() | ||
|
|
||
| i.trackCall("LabelNames") | ||
|
|
||
| if !i.happy { | ||
| return nil, errFail | ||
| } | ||
|
|
||
| _, _, matchers, err := client.FromLabelNamesRequest(req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| response := client.LabelNamesResponse{} | ||
| for _, ts := range i.timeseries { | ||
| if match(ts.Labels, matchers) { | ||
| for _, lbl := range ts.Labels { | ||
| response.LabelNames = append(response.LabelNames, lbl.Name) | ||
| } | ||
| } | ||
| } | ||
| sort.Strings(response.LabelNames) | ||
|
|
||
| return &response, nil | ||
| } | ||
|
|
||
| func (i *mockIngester) MetricsMetadata(ctx context.Context, req *client.MetricsMetadataRequest, opts ...grpc.CallOption) (*client.MetricsMetadataResponse, error) { | ||
| i.Lock() | ||
| defer i.Unlock() | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.