From 1ebd4b1fac45839c4a53808a9f1b19f9b8b6f39d Mon Sep 17 00:00:00 2001 From: Charlie Le Date: Thu, 5 Mar 2026 15:14:03 -0800 Subject: [PATCH 1/3] Add per-tenant TSDB cardinality status API endpoint Expose TSDB head cardinality statistics through a new /api/v1/status/tsdb endpoint, enabling users to identify which metrics, labels, and label-value pairs contribute the most series. This follows the existing UserStats fan-out pattern: ingester calls Head.Stats(), distributor aggregates across the replication set (dividing replicated counts by RF), and an HTTP handler serves JSON with an optional ?limit=N parameter. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Charlie Le --- pkg/api/api.go | 3 + pkg/distributor/distributor.go | 116 ++ pkg/distributor/distributor_test.go | 74 ++ pkg/distributor/http_server.go | 19 + pkg/distributor/http_server_test.go | 67 ++ pkg/ingester/client/cortex_mock_test.go | 5 + pkg/ingester/client/ingester.pb.go | 1338 +++++++++++++++++++++-- pkg/ingester/client/ingester.proto | 21 + pkg/ingester/ingester.go | 52 + pkg/ingester/ingester_test.go | 61 ++ 10 files changed, 1658 insertions(+), 98 deletions(-) create mode 100644 pkg/distributor/http_server_test.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 2971fe87762..ba47d05de2f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -428,6 +428,7 @@ func (a *API) RegisterCompactor(c *compactor.Compactor) { type Distributor interface { querier.Distributor UserStatsHandler(w http.ResponseWriter, r *http.Request) + TSDBStatusHandler(w http.ResponseWriter, r *http.Request) } // RegisterQueryable registers the default routes associated with the querier @@ -438,8 +439,10 @@ func (a *API) RegisterQueryable( ) { // these routes are always registered to the default server a.RegisterRoute("/api/v1/user_stats", http.HandlerFunc(distributor.UserStatsHandler), true, "GET") + a.RegisterRoute("/api/v1/status/tsdb", http.HandlerFunc(distributor.TSDBStatusHandler), true, "GET") a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/user_stats"), http.HandlerFunc(distributor.UserStatsHandler), true, "GET") + a.RegisterRoute(path.Join(a.cfg.LegacyHTTPPrefix, "/api/v1/status/tsdb"), http.HandlerFunc(distributor.TSDBStatusHandler), true, "GET") } // RegisterQueryAPI registers the Prometheus API routes with the provided handler. diff --git a/pkg/distributor/distributor.go b/pkg/distributor/distributor.go index 3d74f36366a..e562f4a76c8 100644 --- a/pkg/distributor/distributor.go +++ b/pkg/distributor/distributor.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "math" "net/http" "slices" "sort" @@ -1676,6 +1677,121 @@ func (d *Distributor) UserStats(ctx context.Context) (*ingester.UserStats, error return totalStats, nil } +// TSDBStatusResult holds the result of a TSDB status query across ingesters. +type TSDBStatusResult struct { + NumSeries uint64 `json:"numSeries"` + MinTime int64 `json:"minTime"` + MaxTime int64 `json:"maxTime"` + NumLabelPairs int32 `json:"numLabelPairs"` + SeriesCountByMetricName []TSDBStatResult `json:"seriesCountByMetricName"` + LabelValueCountByLabelName []TSDBStatResult `json:"labelValueCountByLabelName"` + MemoryInBytesByLabelName []TSDBStatResult `json:"memoryInBytesByLabelName"` + SeriesCountByLabelValuePair []TSDBStatResult `json:"seriesCountByLabelValuePair"` +} + +// TSDBStatResult is a single name/value cardinality stat. +type TSDBStatResult struct { + Name string `json:"name"` + Value uint64 `json:"value"` +} + +// TSDBStatus returns TSDB cardinality statistics for the current tenant, aggregated +// across all ingesters. +func (d *Distributor) TSDBStatus(ctx context.Context, limit int32) (*TSDBStatusResult, error) { + replicationSet, err := d.GetIngestersForMetadata(ctx) + if err != nil { + return nil, err + } + + // Require all ingesters to respond. + replicationSet.MaxErrors = 0 + + req := &ingester_client.TSDBStatusRequest{Limit: limit} + resps, err := d.ForReplicationSet(ctx, replicationSet, false, false, func(ctx context.Context, client ingester_client.IngesterClient) (interface{}, error) { + return client.TSDBStatus(ctx, req) + }) + if err != nil { + return nil, err + } + + // Merge responses from all ingesters. + seriesByMetric := map[string]uint64{} + labelValueCount := map[string]uint64{} + memoryByLabel := map[string]uint64{} + seriesByLabelPair := map[string]uint64{} + + var totalSeries uint64 + var numLabelPairs int32 + minTime := int64(math.MaxInt64) + maxTime := int64(math.MinInt64) + + for _, resp := range resps { + r := resp.(*ingester_client.TSDBStatusResponse) + totalSeries += r.NumSeries + if r.MinTime < minTime { + minTime = r.MinTime + } + if r.MaxTime > maxTime { + maxTime = r.MaxTime + } + if r.NumLabelPairs > numLabelPairs { + numLabelPairs = r.NumLabelPairs + } + for _, item := range r.SeriesCountByMetricName { + seriesByMetric[item.Name] += item.Value + } + for _, item := range r.LabelValueCountByLabelName { + if item.Value > labelValueCount[item.Name] { + labelValueCount[item.Name] = item.Value + } + } + for _, item := range r.MemoryInBytesByLabelName { + memoryByLabel[item.Name] += item.Value + } + for _, item := range r.SeriesCountByLabelValuePair { + seriesByLabelPair[item.Name] += item.Value + } + } + + rf := uint64(d.ingestersRing.ReplicationFactor()) + + result := &TSDBStatusResult{ + NumSeries: totalSeries / rf, + MinTime: minTime, + MaxTime: maxTime, + NumLabelPairs: numLabelPairs, + SeriesCountByMetricName: topNStats(seriesByMetric, int(limit), rf), + LabelValueCountByLabelName: topNStats(labelValueCount, int(limit), 1), // don't divide unique value counts + MemoryInBytesByLabelName: topNStats(memoryByLabel, int(limit), rf), + SeriesCountByLabelValuePair: topNStats(seriesByLabelPair, int(limit), rf), + } + + // If no ingesters responded with valid times, zero them out. + if minTime == math.MaxInt64 { + result.MinTime = 0 + } + if maxTime == math.MinInt64 { + result.MaxTime = 0 + } + + return result, nil +} + +// topNStats sorts a name→count map by count descending, divides by rf, and returns the top n items. +func topNStats(m map[string]uint64, n int, rf uint64) []TSDBStatResult { + items := make([]TSDBStatResult, 0, len(m)) + for name, value := range m { + items = append(items, TSDBStatResult{Name: name, Value: value / rf}) + } + sort.Slice(items, func(i, j int) bool { + return items[i].Value > items[j].Value + }) + if len(items) > n { + items = items[:n] + } + return items +} + // AllUserStats returns statistics about all users. // Note it does not divide by the ReplicationFactor like UserStats() func (d *Distributor) AllUserStats(ctx context.Context) ([]ingester.UserIDStats, int, error) { diff --git a/pkg/distributor/distributor_test.go b/pkg/distributor/distributor_test.go index 2b3b91b0fe3..dd777735cc3 100644 --- a/pkg/distributor/distributor_test.go +++ b/pkg/distributor/distributor_test.go @@ -3700,6 +3700,7 @@ type mockIngester struct { happy atomic.Bool failResp atomic.Error stats client.UsersStatsResponse + tsdbStatus client.TSDBStatusResponse timeseries map[uint32]*cortexpb.PreallocTimeseries metadata map[uint32]map[cortexpb.MetricMetadata]struct{} queryDelay time.Duration @@ -4073,6 +4074,10 @@ func (i *mockIngester) AllUserStats(ctx context.Context, in *client.UserStatsReq return &i.stats, nil } +func (i *mockIngester) TSDBStatus(ctx context.Context, in *client.TSDBStatusRequest, opts ...grpc.CallOption) (*client.TSDBStatusResponse, error) { + return &i.tsdbStatus, nil +} + func match(labels []cortexpb.LabelAdapter, matchers []*labels.Matcher) bool { outer: for _, matcher := range matchers { @@ -4313,6 +4318,75 @@ func TestShardByAllLabelsReturnsWrongResultsForUnsortedLabels(t *testing.T) { assert.NotEqual(t, val1, val2) } +func TestDistributor_TSDBStatus(t *testing.T) { + // Set up 3 ingesters with RF=3 (each ingester has a replica of all data) + distributors, ingesters, _, _ := prepare(t, prepConfig{ + numIngesters: 3, + happyIngesters: 3, + numDistributors: 1, + replicationFactor: 3, + }) + + // Set TSDB status on each mock ingester + for _, ing := range ingesters { + ing.tsdbStatus = client.TSDBStatusResponse{ + NumSeries: 300, + MinTime: 1000, + MaxTime: 2000, + NumLabelPairs: 5, + SeriesCountByMetricName: []*client.TSDBStatItem{ + {Name: "http_requests_total", Value: 150}, + {Name: "process_cpu_seconds", Value: 90}, + {Name: "up", Value: 60}, + }, + LabelValueCountByLabelName: []*client.TSDBStatItem{ + {Name: "instance", Value: 50}, + {Name: "job", Value: 10}, + }, + MemoryInBytesByLabelName: []*client.TSDBStatItem{ + {Name: "instance", Value: 3000}, + {Name: "job", Value: 600}, + }, + SeriesCountByLabelValuePair: []*client.TSDBStatItem{ + {Name: "job=cortex", Value: 210}, + {Name: "job=prometheus", Value: 90}, + }, + } + } + + ctx := user.InjectOrgID(context.Background(), "test") + result, err := distributors[0].TSDBStatus(ctx, 10) + require.NoError(t, err) + + // NumSeries should be summed across ingesters then divided by RF (3*300/3 = 300) + assert.Equal(t, uint64(300), result.NumSeries) + + // MinTime should be min across ingesters + assert.Equal(t, int64(1000), result.MinTime) + // MaxTime should be max across ingesters + assert.Equal(t, int64(2000), result.MaxTime) + + // SeriesCountByMetricName: summed and divided by RF (3*150/3 = 150) + require.Len(t, result.SeriesCountByMetricName, 3) + assert.Equal(t, "http_requests_total", result.SeriesCountByMetricName[0].Name) + assert.Equal(t, uint64(150), result.SeriesCountByMetricName[0].Value) + + // LabelValueCountByLabelName: NOT divided by RF (takes max across ingesters) + require.Len(t, result.LabelValueCountByLabelName, 2) + assert.Equal(t, "instance", result.LabelValueCountByLabelName[0].Name) + assert.Equal(t, uint64(50), result.LabelValueCountByLabelName[0].Value) + + // MemoryInBytesByLabelName: summed and divided by RF + require.Len(t, result.MemoryInBytesByLabelName, 2) + assert.Equal(t, "instance", result.MemoryInBytesByLabelName[0].Name) + assert.Equal(t, uint64(3000), result.MemoryInBytesByLabelName[0].Value) + + // SeriesCountByLabelValuePair: summed and divided by RF + require.Len(t, result.SeriesCountByLabelValuePair, 2) + assert.Equal(t, "job=cortex", result.SeriesCountByLabelValuePair[0].Name) + assert.Equal(t, uint64(210), result.SeriesCountByLabelValuePair[0].Value) +} + func TestSortLabels(t *testing.T) { sorted := []cortexpb.LabelAdapter{ {Name: "__name__", Value: "foo"}, diff --git a/pkg/distributor/http_server.go b/pkg/distributor/http_server.go index 8934f3718e7..f91e677ff34 100644 --- a/pkg/distributor/http_server.go +++ b/pkg/distributor/http_server.go @@ -2,6 +2,7 @@ package distributor import ( "net/http" + "strconv" "github.com/cortexproject/cortex/pkg/util" ) @@ -16,3 +17,21 @@ func (d *Distributor) UserStatsHandler(w http.ResponseWriter, r *http.Request) { util.WriteJSONResponse(w, stats) } + +// TSDBStatusHandler handles TSDB cardinality status requests. +func (d *Distributor) TSDBStatusHandler(w http.ResponseWriter, r *http.Request) { + limit := int32(10) + if v := r.FormValue("limit"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { + limit = int32(n) + } + } + + status, err := d.TSDBStatus(r.Context(), limit) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + util.WriteJSONResponse(w, status) +} diff --git a/pkg/distributor/http_server_test.go b/pkg/distributor/http_server_test.go new file mode 100644 index 00000000000..fec51aceb14 --- /dev/null +++ b/pkg/distributor/http_server_test.go @@ -0,0 +1,67 @@ +package distributor + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/weaveworks/common/user" + + "github.com/cortexproject/cortex/pkg/ingester/client" +) + +func TestTSDBStatusHandler(t *testing.T) { + distributors, ingesters, _, _ := prepare(t, prepConfig{ + numIngesters: 3, + happyIngesters: 3, + numDistributors: 1, + replicationFactor: 3, + }) + + for _, ing := range ingesters { + ing.tsdbStatus = client.TSDBStatusResponse{ + NumSeries: 300, + MinTime: 1000, + MaxTime: 2000, + NumLabelPairs: 5, + SeriesCountByMetricName: []*client.TSDBStatItem{ + {Name: "http_requests_total", Value: 150}, + }, + } + } + + tests := []struct { + name string + queryString string + }{ + {"default limit", ""}, + {"custom limit", "?limit=5"}, + {"invalid limit uses default", "?limit=abc"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ctx := user.InjectOrgID(context.Background(), "test") + req := httptest.NewRequest("GET", "/api/v1/status/tsdb"+tc.queryString, nil) + req = req.WithContext(ctx) + rec := httptest.NewRecorder() + + distributors[0].TSDBStatusHandler(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + + var result TSDBStatusResult + err := json.Unmarshal(rec.Body.Bytes(), &result) + require.NoError(t, err) + assert.Equal(t, uint64(300), result.NumSeries) + assert.Equal(t, int64(1000), result.MinTime) + assert.Equal(t, int64(2000), result.MaxTime) + require.Len(t, result.SeriesCountByMetricName, 1) + assert.Equal(t, "http_requests_total", result.SeriesCountByMetricName[0].Name) + }) + } +} diff --git a/pkg/ingester/client/cortex_mock_test.go b/pkg/ingester/client/cortex_mock_test.go index e9e493a0204..67c82c9f842 100644 --- a/pkg/ingester/client/cortex_mock_test.go +++ b/pkg/ingester/client/cortex_mock_test.go @@ -81,3 +81,8 @@ func (m *IngesterServerMock) MetricsMetadata(ctx context.Context, r *MetricsMeta args := m.Called(ctx, r) return args.Get(0).(*MetricsMetadataResponse), args.Error(1) } + +func (m *IngesterServerMock) TSDBStatus(ctx context.Context, r *TSDBStatusRequest) (*TSDBStatusResponse, error) { + args := m.Called(ctx, r) + return args.Get(0).(*TSDBStatusResponse), args.Error(1) +} diff --git a/pkg/ingester/client/ingester.pb.go b/pkg/ingester/client/ingester.pb.go index 6976ae7ed45..20fde44a6c8 100644 --- a/pkg/ingester/client/ingester.pb.go +++ b/pkg/ingester/client/ingester.pb.go @@ -1475,6 +1475,199 @@ func (m *TimeSeriesFile) GetData() []byte { return nil } +type TSDBStatusRequest struct { + Limit int32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` +} + +func (m *TSDBStatusRequest) Reset() { *m = TSDBStatusRequest{} } +func (*TSDBStatusRequest) ProtoMessage() {} +func (*TSDBStatusRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_60f6df4f3586b478, []int{27} +} +func (m *TSDBStatusRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TSDBStatusRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TSDBStatusRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TSDBStatusRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TSDBStatusRequest.Merge(m, src) +} +func (m *TSDBStatusRequest) XXX_Size() int { + return m.Size() +} +func (m *TSDBStatusRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TSDBStatusRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_TSDBStatusRequest proto.InternalMessageInfo + +func (m *TSDBStatusRequest) GetLimit() int32 { + if m != nil { + return m.Limit + } + return 0 +} + +type TSDBStatusResponse struct { + NumSeries uint64 `protobuf:"varint,1,opt,name=num_series,json=numSeries,proto3" json:"num_series,omitempty"` + MinTime int64 `protobuf:"varint,2,opt,name=min_time,json=minTime,proto3" json:"min_time,omitempty"` + MaxTime int64 `protobuf:"varint,3,opt,name=max_time,json=maxTime,proto3" json:"max_time,omitempty"` + NumLabelPairs int32 `protobuf:"varint,4,opt,name=num_label_pairs,json=numLabelPairs,proto3" json:"num_label_pairs,omitempty"` + SeriesCountByMetricName []*TSDBStatItem `protobuf:"bytes,5,rep,name=series_count_by_metric_name,json=seriesCountByMetricName,proto3" json:"series_count_by_metric_name,omitempty"` + LabelValueCountByLabelName []*TSDBStatItem `protobuf:"bytes,6,rep,name=label_value_count_by_label_name,json=labelValueCountByLabelName,proto3" json:"label_value_count_by_label_name,omitempty"` + MemoryInBytesByLabelName []*TSDBStatItem `protobuf:"bytes,7,rep,name=memory_in_bytes_by_label_name,json=memoryInBytesByLabelName,proto3" json:"memory_in_bytes_by_label_name,omitempty"` + SeriesCountByLabelValuePair []*TSDBStatItem `protobuf:"bytes,8,rep,name=series_count_by_label_value_pair,json=seriesCountByLabelValuePair,proto3" json:"series_count_by_label_value_pair,omitempty"` +} + +func (m *TSDBStatusResponse) Reset() { *m = TSDBStatusResponse{} } +func (*TSDBStatusResponse) ProtoMessage() {} +func (*TSDBStatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_60f6df4f3586b478, []int{28} +} +func (m *TSDBStatusResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TSDBStatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TSDBStatusResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TSDBStatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TSDBStatusResponse.Merge(m, src) +} +func (m *TSDBStatusResponse) XXX_Size() int { + return m.Size() +} +func (m *TSDBStatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TSDBStatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TSDBStatusResponse proto.InternalMessageInfo + +func (m *TSDBStatusResponse) GetNumSeries() uint64 { + if m != nil { + return m.NumSeries + } + return 0 +} + +func (m *TSDBStatusResponse) GetMinTime() int64 { + if m != nil { + return m.MinTime + } + return 0 +} + +func (m *TSDBStatusResponse) GetMaxTime() int64 { + if m != nil { + return m.MaxTime + } + return 0 +} + +func (m *TSDBStatusResponse) GetNumLabelPairs() int32 { + if m != nil { + return m.NumLabelPairs + } + return 0 +} + +func (m *TSDBStatusResponse) GetSeriesCountByMetricName() []*TSDBStatItem { + if m != nil { + return m.SeriesCountByMetricName + } + return nil +} + +func (m *TSDBStatusResponse) GetLabelValueCountByLabelName() []*TSDBStatItem { + if m != nil { + return m.LabelValueCountByLabelName + } + return nil +} + +func (m *TSDBStatusResponse) GetMemoryInBytesByLabelName() []*TSDBStatItem { + if m != nil { + return m.MemoryInBytesByLabelName + } + return nil +} + +func (m *TSDBStatusResponse) GetSeriesCountByLabelValuePair() []*TSDBStatItem { + if m != nil { + return m.SeriesCountByLabelValuePair + } + return nil +} + +type TSDBStatItem struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Value uint64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *TSDBStatItem) Reset() { *m = TSDBStatItem{} } +func (*TSDBStatItem) ProtoMessage() {} +func (*TSDBStatItem) Descriptor() ([]byte, []int) { + return fileDescriptor_60f6df4f3586b478, []int{29} +} +func (m *TSDBStatItem) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TSDBStatItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TSDBStatItem.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TSDBStatItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_TSDBStatItem.Merge(m, src) +} +func (m *TSDBStatItem) XXX_Size() int { + return m.Size() +} +func (m *TSDBStatItem) XXX_DiscardUnknown() { + xxx_messageInfo_TSDBStatItem.DiscardUnknown(m) +} + +var xxx_messageInfo_TSDBStatItem proto.InternalMessageInfo + +func (m *TSDBStatItem) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *TSDBStatItem) GetValue() uint64 { + if m != nil { + return m.Value + } + return 0 +} + func init() { proto.RegisterEnum("cortex.MatchType", MatchType_name, MatchType_value) proto.RegisterType((*ReadRequest)(nil), "cortex.ReadRequest") @@ -1504,102 +1697,119 @@ func init() { proto.RegisterType((*LabelMatchers)(nil), "cortex.LabelMatchers") proto.RegisterType((*LabelMatcher)(nil), "cortex.LabelMatcher") proto.RegisterType((*TimeSeriesFile)(nil), "cortex.TimeSeriesFile") + proto.RegisterType((*TSDBStatusRequest)(nil), "cortex.TSDBStatusRequest") + proto.RegisterType((*TSDBStatusResponse)(nil), "cortex.TSDBStatusResponse") + proto.RegisterType((*TSDBStatItem)(nil), "cortex.TSDBStatItem") } func init() { proto.RegisterFile("ingester.proto", fileDescriptor_60f6df4f3586b478) } var fileDescriptor_60f6df4f3586b478 = []byte{ - // 1439 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x73, 0x13, 0x47, - 0x10, 0xd6, 0xea, 0x65, 0xa9, 0xf5, 0x40, 0x1e, 0x1b, 0x2c, 0x44, 0x58, 0xc1, 0x52, 0x24, 0xaa, - 0x24, 0xc8, 0xe0, 0x24, 0x55, 0x90, 0x07, 0x94, 0x05, 0x06, 0x0c, 0x18, 0xc3, 0xda, 0x40, 0x2a, - 0x95, 0xd4, 0xd6, 0x5a, 0x1a, 0xcb, 0x1b, 0x76, 0xb5, 0xcb, 0xce, 0x88, 0x02, 0x4e, 0x49, 0xe5, - 0x07, 0x24, 0x87, 0xfc, 0x81, 0xdc, 0x72, 0x4d, 0x55, 0x7e, 0x04, 0x47, 0x1f, 0x72, 0xa0, 0x38, - 0xb8, 0x82, 0xb8, 0x24, 0x37, 0xf2, 0x0f, 0x52, 0x3b, 0x33, 0xfb, 0xb4, 0xfc, 0x20, 0x05, 0xb9, - 0x69, 0xbb, 0xbf, 0xe9, 0xe9, 0xfe, 0xe6, 0x9b, 0xe9, 0xb6, 0xa1, 0x6a, 0x0c, 0xfa, 0x98, 0x50, - 0xec, 0xb6, 0x1d, 0xd7, 0xa6, 0x36, 0xca, 0x77, 0x6d, 0x97, 0xe2, 0x47, 0x8d, 0xe9, 0xbe, 0xdd, - 0xb7, 0x99, 0x69, 0xd6, 0xfb, 0xc5, 0xbd, 0x8d, 0x73, 0x7d, 0x83, 0x6e, 0x0c, 0xd7, 0xda, 0x5d, - 0xdb, 0x9a, 0xe5, 0x40, 0xc7, 0xb5, 0xbf, 0xc5, 0x5d, 0x2a, 0xbe, 0x66, 0x9d, 0xfb, 0x7d, 0xdf, - 0xb1, 0x26, 0x7e, 0xf0, 0xa5, 0xca, 0x17, 0x50, 0x52, 0xb1, 0xde, 0x53, 0xf1, 0x83, 0x21, 0x26, - 0x14, 0xb5, 0x61, 0xe2, 0xc1, 0x10, 0xbb, 0x06, 0x26, 0x75, 0xe9, 0x58, 0xa6, 0x55, 0x9a, 0x9b, - 0x6e, 0x0b, 0xf8, 0xed, 0x21, 0x76, 0x1f, 0x0b, 0x98, 0xea, 0x83, 0x94, 0x0b, 0x50, 0xe6, 0xcb, - 0x89, 0x63, 0x0f, 0x08, 0x46, 0xb3, 0x30, 0xe1, 0x62, 0x32, 0x34, 0xa9, 0xbf, 0xfe, 0x60, 0x62, - 0x3d, 0xc7, 0xa9, 0x3e, 0x4a, 0xb9, 0x0e, 0x95, 0x98, 0x07, 0x7d, 0x0a, 0x40, 0x0d, 0x0b, 0x93, - 0x71, 0x49, 0x38, 0x6b, 0xed, 0x55, 0xc3, 0xc2, 0x2b, 0xcc, 0xd7, 0xc9, 0x3e, 0xdd, 0x6a, 0xa6, - 0xd4, 0x08, 0x5a, 0xf9, 0x39, 0x0d, 0xe5, 0x68, 0x9e, 0xe8, 0x43, 0x40, 0x84, 0xea, 0x2e, 0xd5, - 0x18, 0x88, 0xea, 0x96, 0xa3, 0x59, 0x5e, 0x50, 0xa9, 0x95, 0x51, 0x6b, 0xcc, 0xb3, 0xea, 0x3b, - 0x96, 0x08, 0x6a, 0x41, 0x0d, 0x0f, 0x7a, 0x71, 0x6c, 0x9a, 0x61, 0xab, 0x78, 0xd0, 0x8b, 0x22, - 0x4f, 0x43, 0xc1, 0xd2, 0x69, 0x77, 0x03, 0xbb, 0xa4, 0x9e, 0x89, 0xf3, 0x74, 0x43, 0x5f, 0xc3, - 0xe6, 0x12, 0x77, 0xaa, 0x01, 0x0a, 0x3d, 0x81, 0x8c, 0x8a, 0xd7, 0xeb, 0x7f, 0x4f, 0x1c, 0x93, - 0x5a, 0xa5, 0xb9, 0x23, 0x61, 0x41, 0x4b, 0x98, 0x10, 0xbd, 0x8f, 0xef, 0x19, 0x74, 0xa3, 0x33, - 0x5c, 0x57, 0xf1, 0x7a, 0xe7, 0x9a, 0x57, 0xd7, 0xe6, 0x56, 0x53, 0x7a, 0xbe, 0xd5, 0x3c, 0xff, - 0x3a, 0x27, 0xbb, 0x3d, 0x96, 0xea, 0x6d, 0xaa, 0xfc, 0x22, 0xc1, 0xf4, 0xc2, 0x23, 0x6c, 0x39, - 0xa6, 0xee, 0xfe, 0x2f, 0xf4, 0x9c, 0xd9, 0x46, 0xcf, 0xc1, 0x71, 0xf4, 0x90, 0x90, 0x1f, 0xe5, - 0x6b, 0x98, 0x62, 0xa9, 0xad, 0x50, 0x17, 0xeb, 0x56, 0xa0, 0x86, 0x0b, 0x50, 0xea, 0x6e, 0x0c, - 0x07, 0xf7, 0x63, 0x72, 0x98, 0xf1, 0x83, 0x85, 0x62, 0xb8, 0xe8, 0x81, 0x84, 0x22, 0xa2, 0x2b, - 0xae, 0x65, 0x0b, 0xe9, 0x5a, 0x46, 0x59, 0x81, 0x83, 0x09, 0x02, 0xde, 0x80, 0xda, 0xfe, 0x90, - 0x00, 0xb1, 0x72, 0xee, 0xea, 0xe6, 0x10, 0x13, 0x9f, 0xd4, 0xa3, 0x00, 0xa6, 0x67, 0xd5, 0x06, - 0xba, 0x85, 0x19, 0x99, 0x45, 0xb5, 0xc8, 0x2c, 0x37, 0x75, 0x0b, 0xef, 0xc0, 0x79, 0xfa, 0x35, - 0x38, 0xcf, 0xec, 0xc9, 0x79, 0x96, 0x89, 0x6c, 0x2f, 0xce, 0xd1, 0x34, 0xe4, 0x4c, 0xc3, 0x32, - 0x68, 0x3d, 0xc7, 0x22, 0xf2, 0x0f, 0xe5, 0x2c, 0x4c, 0xc5, 0xaa, 0x12, 0x4c, 0x1d, 0x87, 0x32, - 0x2f, 0xeb, 0x21, 0xb3, 0x33, 0xae, 0x8a, 0x6a, 0xc9, 0x0c, 0xa1, 0xca, 0x79, 0x38, 0x1c, 0x59, - 0x99, 0x38, 0xc9, 0x7d, 0xac, 0xff, 0x5d, 0x82, 0xc9, 0x1b, 0x3e, 0x51, 0xe4, 0x6d, 0x8b, 0x34, - 0xa8, 0x3e, 0x13, 0xa9, 0xfe, 0x3f, 0xd0, 0xa8, 0x7c, 0x22, 0x64, 0x20, 0xb2, 0x16, 0xf5, 0x36, - 0xa1, 0x14, 0xca, 0xc0, 0x2f, 0x17, 0x02, 0x1d, 0x10, 0xe5, 0x33, 0xa8, 0x87, 0xcb, 0x12, 0x64, - 0xed, 0xb9, 0x18, 0x41, 0xed, 0x0e, 0xc1, 0xee, 0x0a, 0xd5, 0xa9, 0x4f, 0x94, 0xf2, 0x7d, 0x1a, - 0x26, 0x23, 0x46, 0x11, 0xea, 0xa4, 0xdf, 0x4b, 0x0c, 0x7b, 0xa0, 0xb9, 0x3a, 0xe5, 0x92, 0x94, - 0xd4, 0x4a, 0x60, 0x55, 0x75, 0x8a, 0x3d, 0xd5, 0x0e, 0x86, 0x96, 0x26, 0x2e, 0x82, 0xc7, 0x58, - 0x56, 0x2d, 0x0e, 0x86, 0x16, 0x57, 0xbf, 0x77, 0x08, 0xba, 0x63, 0x68, 0x89, 0x48, 0x19, 0x16, - 0xa9, 0xa6, 0x3b, 0xc6, 0x62, 0x2c, 0x58, 0x1b, 0xa6, 0xdc, 0xa1, 0x89, 0x93, 0xf0, 0x2c, 0x83, - 0x4f, 0x7a, 0xae, 0x38, 0xfe, 0x04, 0x54, 0xf4, 0x2e, 0x35, 0x1e, 0x62, 0x7f, 0xff, 0x1c, 0xdb, - 0xbf, 0xcc, 0x8d, 0x22, 0x85, 0x13, 0x50, 0x31, 0x6d, 0xbd, 0x87, 0x7b, 0xda, 0x9a, 0x69, 0x77, - 0xef, 0x93, 0x7a, 0x9e, 0x83, 0xb8, 0xb1, 0xc3, 0x6c, 0xca, 0x37, 0x30, 0xe5, 0x51, 0xb0, 0x78, - 0x29, 0x4e, 0xc2, 0x0c, 0x4c, 0x0c, 0x09, 0x76, 0x35, 0xa3, 0x27, 0x2e, 0x64, 0xde, 0xfb, 0x5c, - 0xec, 0xa1, 0x53, 0x90, 0xed, 0xe9, 0x54, 0x67, 0x05, 0x97, 0xe6, 0x0e, 0xfb, 0x47, 0xbd, 0x8d, - 0x46, 0x95, 0xc1, 0x94, 0x2b, 0x80, 0x3c, 0x17, 0x89, 0x47, 0x3f, 0x03, 0x39, 0xe2, 0x19, 0xc4, - 0xfb, 0x71, 0x24, 0x1a, 0x25, 0x91, 0x89, 0xca, 0x91, 0xca, 0x53, 0x09, 0xe4, 0x25, 0x4c, 0x5d, - 0xa3, 0x4b, 0x2e, 0xdb, 0x6e, 0x5c, 0x59, 0x6f, 0x59, 0xf7, 0x67, 0xa1, 0xec, 0x4b, 0x57, 0x23, - 0x98, 0xee, 0xfe, 0x40, 0x97, 0x7c, 0xe8, 0x0a, 0xa6, 0xe1, 0x8d, 0xc9, 0x46, 0xdf, 0x8b, 0xeb, - 0xd0, 0xdc, 0xb1, 0x12, 0x41, 0x50, 0x0b, 0xf2, 0x16, 0x83, 0x08, 0x86, 0x6a, 0xd1, 0xf6, 0xe7, - 0xd9, 0x55, 0xe1, 0x57, 0x6e, 0xc3, 0xc9, 0x1d, 0x82, 0x25, 0x6e, 0xc8, 0xfe, 0x43, 0x3a, 0x70, - 0x48, 0x84, 0x5c, 0xc2, 0x54, 0xf7, 0x8e, 0xd1, 0x67, 0x38, 0xa8, 0x47, 0x8a, 0xbe, 0x00, 0x2d, - 0xa8, 0xb1, 0x1f, 0x9a, 0x83, 0x5d, 0x4d, 0xec, 0x21, 0x98, 0x64, 0xf6, 0x5b, 0xd8, 0xe5, 0xf1, - 0xd0, 0xa1, 0x20, 0x87, 0x0c, 0x17, 0x95, 0xd8, 0x71, 0x19, 0x66, 0xb6, 0xed, 0x28, 0xd2, 0xfe, - 0x18, 0x0a, 0x96, 0xb0, 0x89, 0xc4, 0xeb, 0xc9, 0xc4, 0x83, 0x35, 0x01, 0x52, 0xf9, 0x47, 0x82, - 0x03, 0x89, 0x5e, 0xe7, 0xa5, 0xb9, 0xee, 0xda, 0x96, 0xe6, 0x0f, 0x8a, 0xa1, 0xb6, 0xab, 0x9e, - 0x7d, 0x51, 0x98, 0x17, 0x7b, 0x51, 0xf1, 0xa7, 0x63, 0xe2, 0x1f, 0x40, 0x9e, 0x3d, 0x29, 0x7e, - 0x93, 0x9e, 0x0a, 0x53, 0x61, 0xd4, 0xdf, 0xd2, 0x0d, 0xb7, 0x33, 0xef, 0xf5, 0xbd, 0xe7, 0x5b, - 0xcd, 0xd7, 0x9a, 0x31, 0xf9, 0xfa, 0xf9, 0x9e, 0xee, 0x50, 0xec, 0xaa, 0x62, 0x17, 0xf4, 0x01, - 0xe4, 0x79, 0x6b, 0xae, 0x67, 0xd9, 0x7e, 0x15, 0x5f, 0x73, 0xd1, 0xee, 0x2d, 0x20, 0xca, 0x8f, - 0x12, 0xe4, 0x78, 0xa5, 0x6f, 0xeb, 0x22, 0x34, 0xa0, 0x80, 0x07, 0x5d, 0xbb, 0x67, 0x0c, 0xfa, - 0xec, 0x00, 0x73, 0x6a, 0xf0, 0x8d, 0x90, 0x78, 0x17, 0x3c, 0xa5, 0x97, 0xc5, 0xe5, 0x9f, 0x87, - 0x4a, 0x4c, 0x91, 0xb1, 0x29, 0x50, 0xda, 0xcf, 0x14, 0xa8, 0x68, 0x50, 0x8e, 0x7a, 0xd0, 0x49, - 0xc8, 0xd2, 0xc7, 0x0e, 0x7f, 0x92, 0xab, 0x73, 0x93, 0xfe, 0x6a, 0xe6, 0x5e, 0x7d, 0xec, 0x60, - 0x95, 0xb9, 0xbd, 0x6c, 0xd8, 0x30, 0xc1, 0x8f, 0x8f, 0xfd, 0xf6, 0xc4, 0xcb, 0x3a, 0xa9, 0xd0, - 0x1e, 0xff, 0x50, 0x7e, 0x90, 0xa0, 0x1a, 0x2a, 0xe5, 0xb2, 0x61, 0xe2, 0x37, 0x21, 0x94, 0x06, - 0x14, 0xd6, 0x0d, 0x13, 0xb3, 0x1c, 0xf8, 0x76, 0xc1, 0xf7, 0x38, 0xa6, 0xde, 0xbf, 0x06, 0xc5, - 0xa0, 0x04, 0x54, 0x84, 0xdc, 0xc2, 0xed, 0x3b, 0xf3, 0x37, 0x6a, 0x29, 0x54, 0x81, 0xe2, 0xcd, - 0xe5, 0x55, 0x8d, 0x7f, 0x4a, 0xe8, 0x00, 0x94, 0xd4, 0x85, 0x2b, 0x0b, 0x5f, 0x6a, 0x4b, 0xf3, - 0xab, 0x17, 0xaf, 0xd6, 0xd2, 0x08, 0x41, 0x95, 0x1b, 0x6e, 0x2e, 0x0b, 0x5b, 0x66, 0xee, 0xb7, - 0x02, 0x14, 0xfc, 0x1c, 0xd1, 0x39, 0xc8, 0xde, 0x1a, 0x92, 0x0d, 0x74, 0x28, 0x54, 0xea, 0x3d, - 0xd7, 0xa0, 0x58, 0xdc, 0xe8, 0xc6, 0xcc, 0x36, 0x3b, 0xbf, 0x77, 0x4a, 0x0a, 0x2d, 0x02, 0x78, - 0x4b, 0xf9, 0x33, 0x82, 0xde, 0x09, 0x81, 0xdc, 0xb2, 0xcf, 0x30, 0x2d, 0xe9, 0xb4, 0x84, 0x2e, - 0x41, 0x29, 0x32, 0xab, 0xa2, 0xb1, 0x7f, 0x22, 0x35, 0x8e, 0xc4, 0xac, 0xf1, 0xd7, 0x4b, 0x49, - 0x9d, 0x96, 0xd0, 0x32, 0x54, 0x99, 0xcb, 0x1f, 0x4c, 0x49, 0x90, 0x54, 0x7b, 0xdc, 0xb0, 0xde, - 0x38, 0xba, 0x83, 0x37, 0xa8, 0xf0, 0x2a, 0x94, 0x22, 0xe3, 0x17, 0x6a, 0xc4, 0xb4, 0x18, 0x9b, - 0x51, 0xc3, 0xe4, 0xc6, 0x4c, 0x7a, 0x4a, 0x0a, 0xdd, 0x15, 0x73, 0x58, 0x74, 0x90, 0xdb, 0x35, - 0xde, 0xf1, 0x31, 0xbe, 0x31, 0x25, 0x2f, 0x00, 0x84, 0x23, 0x0f, 0x3a, 0x1c, 0x5b, 0x14, 0x9d, - 0xf9, 0x1a, 0x8d, 0x71, 0xae, 0x20, 0xbd, 0x15, 0xa8, 0x25, 0x27, 0xa7, 0xdd, 0x82, 0x1d, 0xdb, - 0xee, 0x1a, 0x93, 0x5b, 0x07, 0x8a, 0x41, 0xd7, 0x47, 0xf5, 0x31, 0x83, 0x00, 0x0f, 0xb6, 0xf3, - 0x88, 0xa0, 0xa4, 0xd0, 0x65, 0x28, 0xcf, 0x9b, 0xe6, 0x7e, 0xc2, 0x34, 0xa2, 0x1e, 0x92, 0x8c, - 0x63, 0x06, 0x0d, 0x24, 0xd9, 0x05, 0xd1, 0xbb, 0xc1, 0x1b, 0xb1, 0xeb, 0xf4, 0xd0, 0x78, 0x6f, - 0x4f, 0x5c, 0xb0, 0xdb, 0x13, 0x38, 0xba, 0x6b, 0xcf, 0xdd, 0xf7, 0x9e, 0xa7, 0xf6, 0xc0, 0x8d, - 0x61, 0x7d, 0x15, 0x0e, 0x24, 0x5a, 0x25, 0x92, 0x13, 0x51, 0x12, 0x5d, 0xbb, 0xd1, 0xdc, 0xd1, - 0xef, 0xc7, 0xed, 0x7c, 0xbe, 0xf9, 0x42, 0x4e, 0x3d, 0x7b, 0x21, 0xa7, 0x5e, 0xbd, 0x90, 0xa5, - 0xef, 0x46, 0xb2, 0xf4, 0xeb, 0x48, 0x96, 0x9e, 0x8e, 0x64, 0x69, 0x73, 0x24, 0x4b, 0x7f, 0x8e, - 0x64, 0xe9, 0xaf, 0x91, 0x9c, 0x7a, 0x35, 0x92, 0xa5, 0x9f, 0x5e, 0xca, 0xa9, 0xcd, 0x97, 0x72, - 0xea, 0xd9, 0x4b, 0x39, 0xf5, 0x55, 0xbe, 0x6b, 0x1a, 0x78, 0x40, 0xd7, 0xf2, 0xec, 0x3f, 0x23, - 0x1f, 0xfd, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x76, 0xeb, 0xb3, 0x84, 0x11, 0x00, 0x00, + // 1656 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcb, 0x72, 0x13, 0x47, + 0x17, 0xd6, 0x58, 0x17, 0x4b, 0x47, 0x92, 0x2d, 0xb7, 0x0d, 0x96, 0xe5, 0xdf, 0x92, 0x19, 0x0a, + 0x7e, 0xff, 0x17, 0x6c, 0x70, 0x92, 0x2a, 0xc8, 0x05, 0xca, 0x02, 0x03, 0x02, 0x8c, 0x61, 0x6c, + 0x20, 0xd7, 0x9a, 0x1a, 0x49, 0x6d, 0x7b, 0xc2, 0xdc, 0x98, 0xe9, 0xa1, 0x6c, 0x56, 0x49, 0xe5, + 0x01, 0x92, 0x45, 0x5e, 0x20, 0xbb, 0x3c, 0x40, 0x1e, 0x82, 0xa5, 0x17, 0x59, 0x50, 0x2c, 0x5c, + 0xc1, 0x6c, 0x92, 0x1d, 0xa9, 0xca, 0x22, 0xcb, 0xd4, 0x74, 0xf7, 0x5c, 0x25, 0xcb, 0x26, 0x05, + 0xd9, 0x69, 0xce, 0xad, 0xcf, 0xf9, 0xfa, 0xeb, 0x3e, 0xa7, 0x05, 0x23, 0xaa, 0xb1, 0x89, 0x1d, + 0x82, 0xed, 0x79, 0xcb, 0x36, 0x89, 0x89, 0x72, 0x1d, 0xd3, 0x26, 0x78, 0xbb, 0x36, 0xb1, 0x69, + 0x6e, 0x9a, 0x54, 0xb4, 0xe0, 0xfd, 0x62, 0xda, 0xda, 0x85, 0x4d, 0x95, 0x6c, 0xb9, 0xed, 0xf9, + 0x8e, 0xa9, 0x2f, 0x30, 0x43, 0xcb, 0x36, 0xbf, 0xc4, 0x1d, 0xc2, 0xbf, 0x16, 0xac, 0x87, 0x9b, + 0xbe, 0xa2, 0xcd, 0x7f, 0x30, 0x57, 0xf1, 0x23, 0x28, 0x4a, 0x58, 0xe9, 0x4a, 0xf8, 0x91, 0x8b, + 0x1d, 0x82, 0xe6, 0x61, 0xf8, 0x91, 0x8b, 0x6d, 0x15, 0x3b, 0x55, 0x61, 0x36, 0x3d, 0x57, 0x5c, + 0x9c, 0x98, 0xe7, 0xe6, 0x77, 0x5d, 0x6c, 0xef, 0x70, 0x33, 0xc9, 0x37, 0x12, 0x2f, 0x41, 0x89, + 0xb9, 0x3b, 0x96, 0x69, 0x38, 0x18, 0x2d, 0xc0, 0xb0, 0x8d, 0x1d, 0x57, 0x23, 0xbe, 0xff, 0xb1, + 0x84, 0x3f, 0xb3, 0x93, 0x7c, 0x2b, 0xf1, 0x26, 0x94, 0x63, 0x1a, 0xf4, 0x3e, 0x00, 0x51, 0x75, + 0xec, 0xf4, 0x4b, 0xc2, 0x6a, 0xcf, 0xaf, 0xab, 0x3a, 0x5e, 0xa3, 0xba, 0x66, 0xe6, 0xe9, 0x5e, + 0x23, 0x25, 0x45, 0xac, 0xc5, 0xef, 0x87, 0xa0, 0x14, 0xcd, 0x13, 0xfd, 0x1f, 0x90, 0x43, 0x14, + 0x9b, 0xc8, 0xd4, 0x88, 0x28, 0xba, 0x25, 0xeb, 0x5e, 0x50, 0x61, 0x2e, 0x2d, 0x55, 0xa8, 0x66, + 0xdd, 0x57, 0xac, 0x38, 0x68, 0x0e, 0x2a, 0xd8, 0xe8, 0xc6, 0x6d, 0x87, 0xa8, 0xed, 0x08, 0x36, + 0xba, 0x51, 0xcb, 0xb3, 0x90, 0xd7, 0x15, 0xd2, 0xd9, 0xc2, 0xb6, 0x53, 0x4d, 0xc7, 0x71, 0xba, + 0xa5, 0xb4, 0xb1, 0xb6, 0xc2, 0x94, 0x52, 0x60, 0x85, 0x9e, 0x40, 0x5a, 0xc2, 0x1b, 0xd5, 0xdf, + 0x86, 0x67, 0x85, 0xb9, 0xe2, 0xe2, 0x74, 0x58, 0xd0, 0x0a, 0x76, 0x1c, 0x65, 0x13, 0x3f, 0x50, + 0xc9, 0x56, 0xd3, 0xdd, 0x90, 0xf0, 0x46, 0xf3, 0x86, 0x57, 0xd7, 0xee, 0x5e, 0x43, 0x78, 0xbe, + 0xd7, 0xb8, 0xf8, 0x3a, 0x3b, 0xdb, 0x1b, 0x4b, 0xf2, 0x16, 0x15, 0x7f, 0x10, 0x60, 0x62, 0x79, + 0x1b, 0xeb, 0x96, 0xa6, 0xd8, 0xff, 0x08, 0x3c, 0xe7, 0x7a, 0xe0, 0x39, 0xd6, 0x0f, 0x1e, 0x27, + 0xc4, 0x47, 0xfc, 0x1c, 0xc6, 0x69, 0x6a, 0x6b, 0xc4, 0xc6, 0x8a, 0x1e, 0xb0, 0xe1, 0x12, 0x14, + 0x3b, 0x5b, 0xae, 0xf1, 0x30, 0x46, 0x87, 0x49, 0x3f, 0x58, 0x48, 0x86, 0xcb, 0x9e, 0x11, 0x67, + 0x44, 0xd4, 0xe3, 0x46, 0x26, 0x3f, 0x54, 0x49, 0x8b, 0x6b, 0x70, 0x2c, 0x01, 0xc0, 0x1b, 0x60, + 0xdb, 0xcf, 0x02, 0x20, 0x5a, 0xce, 0x7d, 0x45, 0x73, 0xb1, 0xe3, 0x83, 0x3a, 0x03, 0xa0, 0x79, + 0x52, 0xd9, 0x50, 0x74, 0x4c, 0xc1, 0x2c, 0x48, 0x05, 0x2a, 0xb9, 0xad, 0xe8, 0xf8, 0x00, 0xcc, + 0x87, 0x5e, 0x03, 0xf3, 0xf4, 0xa1, 0x98, 0x67, 0x28, 0xc9, 0x0e, 0xc3, 0x1c, 0x4d, 0x40, 0x56, + 0x53, 0x75, 0x95, 0x54, 0xb3, 0x34, 0x22, 0xfb, 0x10, 0xcf, 0xc3, 0x78, 0xac, 0x2a, 0x8e, 0xd4, + 0x09, 0x28, 0xb1, 0xb2, 0x1e, 0x53, 0x39, 0xc5, 0xaa, 0x20, 0x15, 0xb5, 0xd0, 0x54, 0xbc, 0x08, + 0x53, 0x11, 0xcf, 0xc4, 0x4e, 0x1e, 0xc1, 0xff, 0x27, 0x01, 0xc6, 0x6e, 0xf9, 0x40, 0x39, 0x6f, + 0x9b, 0xa4, 0x41, 0xf5, 0xe9, 0x48, 0xf5, 0x7f, 0x03, 0x46, 0xf1, 0x3d, 0x4e, 0x03, 0x9e, 0x35, + 0xaf, 0xb7, 0x01, 0xc5, 0x90, 0x06, 0x7e, 0xb9, 0x10, 0xf0, 0xc0, 0x11, 0x3f, 0x80, 0x6a, 0xe8, + 0x96, 0x00, 0xeb, 0x50, 0x67, 0x04, 0x95, 0x7b, 0x0e, 0xb6, 0xd7, 0x88, 0x42, 0x7c, 0xa0, 0xc4, + 0xaf, 0x87, 0x60, 0x2c, 0x22, 0xe4, 0xa1, 0x4e, 0xf9, 0xbd, 0x44, 0x35, 0x0d, 0xd9, 0x56, 0x08, + 0xa3, 0xa4, 0x20, 0x95, 0x03, 0xa9, 0xa4, 0x10, 0xec, 0xb1, 0xd6, 0x70, 0x75, 0x99, 0x1f, 0x04, + 0x0f, 0xb1, 0x8c, 0x54, 0x30, 0x5c, 0x9d, 0xb1, 0xdf, 0xdb, 0x04, 0xc5, 0x52, 0xe5, 0x44, 0xa4, + 0x34, 0x8d, 0x54, 0x51, 0x2c, 0xb5, 0x15, 0x0b, 0x36, 0x0f, 0xe3, 0xb6, 0xab, 0xe1, 0xa4, 0x79, + 0x86, 0x9a, 0x8f, 0x79, 0xaa, 0xb8, 0xfd, 0x49, 0x28, 0x2b, 0x1d, 0xa2, 0x3e, 0xc6, 0xfe, 0xfa, + 0x59, 0xba, 0x7e, 0x89, 0x09, 0x79, 0x0a, 0x27, 0xa1, 0xac, 0x99, 0x4a, 0x17, 0x77, 0xe5, 0xb6, + 0x66, 0x76, 0x1e, 0x3a, 0xd5, 0x1c, 0x33, 0x62, 0xc2, 0x26, 0x95, 0x89, 0x5f, 0xc0, 0xb8, 0x07, + 0x41, 0xeb, 0x4a, 0x1c, 0x84, 0x49, 0x18, 0x76, 0x1d, 0x6c, 0xcb, 0x6a, 0x97, 0x1f, 0xc8, 0x9c, + 0xf7, 0xd9, 0xea, 0xa2, 0x33, 0x90, 0xe9, 0x2a, 0x44, 0xa1, 0x05, 0x17, 0x17, 0xa7, 0xfc, 0xad, + 0xee, 0x81, 0x51, 0xa2, 0x66, 0xe2, 0x35, 0x40, 0x9e, 0xca, 0x89, 0x47, 0x3f, 0x07, 0x59, 0xc7, + 0x13, 0xf0, 0xfb, 0x63, 0x3a, 0x1a, 0x25, 0x91, 0x89, 0xc4, 0x2c, 0xc5, 0xa7, 0x02, 0xd4, 0x57, + 0x30, 0xb1, 0xd5, 0x8e, 0x73, 0xd5, 0xb4, 0xe3, 0xcc, 0x7a, 0xcb, 0xbc, 0x3f, 0x0f, 0x25, 0x9f, + 0xba, 0xb2, 0x83, 0xc9, 0xe0, 0x0b, 0xba, 0xe8, 0x9b, 0xae, 0x61, 0x12, 0x9e, 0x98, 0x4c, 0xf4, + 0xbe, 0xb8, 0x09, 0x8d, 0x03, 0x2b, 0xe1, 0x00, 0xcd, 0x41, 0x4e, 0xa7, 0x26, 0x1c, 0xa1, 0x4a, + 0xb4, 0xfd, 0x79, 0x72, 0x89, 0xeb, 0xc5, 0xbb, 0x70, 0xea, 0x80, 0x60, 0x89, 0x13, 0x72, 0xf4, + 0x90, 0x16, 0x1c, 0xe7, 0x21, 0x57, 0x30, 0x51, 0xbc, 0x6d, 0xf4, 0x11, 0x0e, 0xea, 0x11, 0xa2, + 0x37, 0xc0, 0x1c, 0x54, 0xe8, 0x0f, 0xd9, 0xc2, 0xb6, 0xcc, 0xd7, 0xe0, 0x48, 0x52, 0xf9, 0x1d, + 0x6c, 0xb3, 0x78, 0xe8, 0x78, 0x90, 0x43, 0x9a, 0x91, 0x8a, 0xaf, 0xb8, 0x0a, 0x93, 0x3d, 0x2b, + 0xf2, 0xb4, 0xdf, 0x85, 0xbc, 0xce, 0x65, 0x3c, 0xf1, 0x6a, 0x32, 0xf1, 0xc0, 0x27, 0xb0, 0x14, + 0x7f, 0x17, 0x60, 0x34, 0xd1, 0xeb, 0xbc, 0x34, 0x37, 0x6c, 0x53, 0x97, 0xfd, 0x41, 0x31, 0xe4, + 0xf6, 0x88, 0x27, 0x6f, 0x71, 0x71, 0xab, 0x1b, 0x25, 0xff, 0x50, 0x8c, 0xfc, 0x06, 0xe4, 0xe8, + 0x95, 0xe2, 0x37, 0xe9, 0xf1, 0x30, 0x15, 0x0a, 0xfd, 0x1d, 0x45, 0xb5, 0x9b, 0x4b, 0x5e, 0xdf, + 0x7b, 0xbe, 0xd7, 0x78, 0xad, 0x19, 0x93, 0xf9, 0x2f, 0x75, 0x15, 0x8b, 0x60, 0x5b, 0xe2, 0xab, + 0xa0, 0xff, 0x41, 0x8e, 0xb5, 0xe6, 0x6a, 0x86, 0xae, 0x57, 0xf6, 0x39, 0x17, 0xed, 0xde, 0xdc, + 0x44, 0xfc, 0x56, 0x80, 0x2c, 0xab, 0xf4, 0x6d, 0x1d, 0x84, 0x1a, 0xe4, 0xb1, 0xd1, 0x31, 0xbb, + 0xaa, 0xb1, 0x49, 0x37, 0x30, 0x2b, 0x05, 0xdf, 0x08, 0xf1, 0x7b, 0xc1, 0x63, 0x7a, 0x89, 0x1f, + 0xfe, 0x25, 0x28, 0xc7, 0x18, 0x19, 0x9b, 0x02, 0x85, 0xa3, 0x4c, 0x81, 0xa2, 0x0c, 0xa5, 0xa8, + 0x06, 0x9d, 0x82, 0x0c, 0xd9, 0xb1, 0xd8, 0x95, 0x3c, 0xb2, 0x38, 0xe6, 0x7b, 0x53, 0xf5, 0xfa, + 0x8e, 0x85, 0x25, 0xaa, 0xf6, 0xb2, 0xa1, 0xc3, 0x04, 0xdb, 0x3e, 0xfa, 0xdb, 0x23, 0x2f, 0xed, + 0xa4, 0x9c, 0x7b, 0xec, 0x43, 0xfc, 0x46, 0x80, 0x91, 0x90, 0x29, 0x57, 0x55, 0x0d, 0xbf, 0x09, + 0xa2, 0xd4, 0x20, 0xbf, 0xa1, 0x6a, 0x98, 0xe6, 0xc0, 0x96, 0x0b, 0xbe, 0xfb, 0x22, 0xf5, 0x1f, + 0x18, 0x5b, 0x5f, 0xbb, 0xd2, 0xf4, 0x6e, 0x3e, 0xd7, 0xe9, 0x7b, 0xda, 0xb2, 0xfe, 0xed, 0xf1, + 0x47, 0x1a, 0x50, 0xd4, 0x96, 0x9f, 0x93, 0x78, 0x3b, 0x12, 0x92, 0xed, 0x68, 0x0a, 0xf2, 0xba, + 0x6a, 0xd0, 0x4d, 0xe6, 0x9b, 0x3b, 0xac, 0xab, 0x86, 0x57, 0x38, 0x55, 0x29, 0xdb, 0x4c, 0x95, + 0xe6, 0x2a, 0x65, 0x9b, 0xaa, 0x4e, 0xc3, 0xa8, 0x17, 0x94, 0x75, 0x56, 0x4b, 0x51, 0x79, 0x8b, + 0xcf, 0x4a, 0x65, 0xc3, 0xd5, 0x03, 0xc6, 0x3b, 0x48, 0x82, 0x69, 0xb6, 0xb0, 0xdc, 0x31, 0x5d, + 0x83, 0xc8, 0xed, 0x1d, 0x7e, 0x0f, 0xb0, 0x91, 0x2e, 0x1b, 0xdf, 0x6a, 0x3f, 0xfb, 0x16, 0xc1, + 0xba, 0x34, 0xc9, 0x1c, 0x2f, 0x7b, 0x7e, 0xcd, 0x1d, 0x76, 0xa0, 0xe9, 0xd8, 0xf7, 0x09, 0x34, + 0x22, 0xe3, 0x4f, 0x18, 0x38, 0x32, 0x2a, 0xe6, 0x06, 0xc4, 0xad, 0x85, 0x73, 0x12, 0x8f, 0x1d, + 0xcc, 0x0e, 0xe8, 0x1e, 0xcc, 0xe8, 0x58, 0x37, 0xed, 0x1d, 0x59, 0x35, 0xe4, 0xf6, 0x0e, 0xc1, + 0x4e, 0x22, 0xf0, 0xf0, 0x80, 0xc0, 0x55, 0xe6, 0xda, 0x32, 0x9a, 0x9e, 0x63, 0x34, 0xec, 0x67, + 0x30, 0x9b, 0x44, 0x21, 0x5a, 0x81, 0x87, 0x5f, 0x35, 0x3f, 0x20, 0xf2, 0x74, 0x0c, 0x8a, 0x70, + 0x30, 0xf4, 0x30, 0x16, 0xcf, 0x43, 0x29, 0x6a, 0x1c, 0x30, 0x5c, 0xe8, 0xc7, 0x70, 0x36, 0x8d, + 0xb0, 0x8f, 0xff, 0xde, 0x80, 0x42, 0x70, 0x3c, 0x50, 0x01, 0xb2, 0xcb, 0x77, 0xef, 0x2d, 0xdd, + 0xaa, 0xa4, 0x50, 0x19, 0x0a, 0xb7, 0x57, 0xd7, 0x65, 0xf6, 0x29, 0xa0, 0x51, 0x28, 0x4a, 0xcb, + 0xd7, 0x96, 0x3f, 0x96, 0x57, 0x96, 0xd6, 0x2f, 0x5f, 0xaf, 0x0c, 0x21, 0x04, 0x23, 0x4c, 0x70, + 0x7b, 0x95, 0xcb, 0xd2, 0x8b, 0x7f, 0xe6, 0x21, 0xef, 0xf3, 0x1f, 0x5d, 0x80, 0xcc, 0x1d, 0xd7, + 0xd9, 0x42, 0xc7, 0xc3, 0x5b, 0xf0, 0x81, 0xad, 0x12, 0xcc, 0xf9, 0x5b, 0x9b, 0xec, 0x91, 0x33, + 0xae, 0x8a, 0x29, 0xd4, 0x02, 0xf0, 0x5c, 0x59, 0x8b, 0x42, 0xff, 0x0a, 0x0d, 0x99, 0xe4, 0x88, + 0x61, 0xe6, 0x84, 0xb3, 0x02, 0xba, 0x02, 0xc5, 0xc8, 0x3b, 0x08, 0xf5, 0x7d, 0x7e, 0xd7, 0xa6, + 0x63, 0xd2, 0x78, 0x67, 0x14, 0x53, 0x67, 0x05, 0xb4, 0x0a, 0x23, 0x54, 0xe5, 0x3f, 0x7a, 0x9c, + 0x20, 0xa9, 0xf9, 0x7e, 0x0f, 0xc1, 0xda, 0xcc, 0x01, 0xda, 0xa0, 0xc2, 0xeb, 0x50, 0x8c, 0x8c, + 0xf6, 0xa8, 0x16, 0xbb, 0xe7, 0x62, 0xef, 0x9f, 0x30, 0xb9, 0x3e, 0xaf, 0x08, 0x31, 0x85, 0xee, + 0xf3, 0x19, 0x3f, 0xfa, 0x48, 0x18, 0x18, 0xef, 0x44, 0x1f, 0x5d, 0x9f, 0x92, 0x97, 0x01, 0xc2, + 0x71, 0x1a, 0x4d, 0xc5, 0x9c, 0xa2, 0xef, 0x89, 0x5a, 0xad, 0x9f, 0x2a, 0x48, 0x6f, 0x0d, 0x2a, + 0xc9, 0xa9, 0x7c, 0x50, 0xb0, 0xd9, 0x5e, 0x55, 0x9f, 0xdc, 0x9a, 0x50, 0x08, 0x26, 0x4a, 0x54, + 0xed, 0x33, 0x64, 0xb2, 0x60, 0x07, 0x8f, 0x9f, 0x62, 0x0a, 0x5d, 0x85, 0xd2, 0x92, 0xa6, 0x1d, + 0x25, 0x4c, 0x2d, 0xaa, 0x71, 0x92, 0x71, 0xb4, 0x60, 0x38, 0x49, 0x4e, 0x58, 0xe8, 0x74, 0xd0, + 0x7f, 0x06, 0x4e, 0xa6, 0xb5, 0x7f, 0x1f, 0x6a, 0x17, 0xac, 0xf6, 0x04, 0x66, 0x06, 0xce, 0x73, + 0x47, 0x5e, 0xf3, 0xcc, 0x21, 0x76, 0x7d, 0x50, 0x5f, 0x87, 0xd1, 0xc4, 0x18, 0x86, 0xea, 0x89, + 0x28, 0x89, 0x89, 0xb0, 0xd6, 0x38, 0x50, 0x1f, 0x54, 0xb4, 0x0c, 0x10, 0xf6, 0xab, 0x90, 0x1a, + 0x3d, 0xfd, 0x2e, 0xdc, 0x86, 0xde, 0xf6, 0x26, 0xa6, 0x9a, 0x1f, 0xee, 0xbe, 0xa8, 0xa7, 0x9e, + 0xbd, 0xa8, 0xa7, 0x5e, 0xbd, 0xa8, 0x0b, 0x5f, 0xed, 0xd7, 0x85, 0x1f, 0xf7, 0xeb, 0xc2, 0xd3, + 0xfd, 0xba, 0xb0, 0xbb, 0x5f, 0x17, 0x7e, 0xd9, 0xaf, 0x0b, 0xbf, 0xee, 0xd7, 0x53, 0xaf, 0xf6, + 0xeb, 0xc2, 0x77, 0x2f, 0xeb, 0xa9, 0xdd, 0x97, 0xf5, 0xd4, 0xb3, 0x97, 0xf5, 0xd4, 0xa7, 0xb9, + 0x8e, 0xa6, 0x62, 0x83, 0xb4, 0x73, 0xf4, 0xcf, 0xbb, 0x77, 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, + 0x96, 0x7d, 0x7f, 0xec, 0x27, 0x14, 0x00, 0x00, } func (x MatchType) String() string { @@ -2451,6 +2661,122 @@ func (this *TimeSeriesFile) Equal(that interface{}) bool { } return true } +func (this *TSDBStatusRequest) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TSDBStatusRequest) + if !ok { + that2, ok := that.(TSDBStatusRequest) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Limit != that1.Limit { + return false + } + return true +} +func (this *TSDBStatusResponse) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TSDBStatusResponse) + if !ok { + that2, ok := that.(TSDBStatusResponse) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.NumSeries != that1.NumSeries { + return false + } + if this.MinTime != that1.MinTime { + return false + } + if this.MaxTime != that1.MaxTime { + return false + } + if this.NumLabelPairs != that1.NumLabelPairs { + return false + } + if len(this.SeriesCountByMetricName) != len(that1.SeriesCountByMetricName) { + return false + } + for i := range this.SeriesCountByMetricName { + if !this.SeriesCountByMetricName[i].Equal(that1.SeriesCountByMetricName[i]) { + return false + } + } + if len(this.LabelValueCountByLabelName) != len(that1.LabelValueCountByLabelName) { + return false + } + for i := range this.LabelValueCountByLabelName { + if !this.LabelValueCountByLabelName[i].Equal(that1.LabelValueCountByLabelName[i]) { + return false + } + } + if len(this.MemoryInBytesByLabelName) != len(that1.MemoryInBytesByLabelName) { + return false + } + for i := range this.MemoryInBytesByLabelName { + if !this.MemoryInBytesByLabelName[i].Equal(that1.MemoryInBytesByLabelName[i]) { + return false + } + } + if len(this.SeriesCountByLabelValuePair) != len(that1.SeriesCountByLabelValuePair) { + return false + } + for i := range this.SeriesCountByLabelValuePair { + if !this.SeriesCountByLabelValuePair[i].Equal(that1.SeriesCountByLabelValuePair[i]) { + return false + } + } + return true +} +func (this *TSDBStatItem) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TSDBStatItem) + if !ok { + that2, ok := that.(TSDBStatItem) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Name != that1.Name { + return false + } + if this.Value != that1.Value { + return false + } + return true +} func (this *ReadRequest) GoString() string { if this == nil { return "nil" @@ -2804,6 +3130,52 @@ func (this *TimeSeriesFile) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *TSDBStatusRequest) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 5) + s = append(s, "&client.TSDBStatusRequest{") + s = append(s, "Limit: "+fmt.Sprintf("%#v", this.Limit)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} +func (this *TSDBStatusResponse) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 12) + s = append(s, "&client.TSDBStatusResponse{") + s = append(s, "NumSeries: "+fmt.Sprintf("%#v", this.NumSeries)+",\n") + s = append(s, "MinTime: "+fmt.Sprintf("%#v", this.MinTime)+",\n") + s = append(s, "MaxTime: "+fmt.Sprintf("%#v", this.MaxTime)+",\n") + s = append(s, "NumLabelPairs: "+fmt.Sprintf("%#v", this.NumLabelPairs)+",\n") + if this.SeriesCountByMetricName != nil { + s = append(s, "SeriesCountByMetricName: "+fmt.Sprintf("%#v", this.SeriesCountByMetricName)+",\n") + } + if this.LabelValueCountByLabelName != nil { + s = append(s, "LabelValueCountByLabelName: "+fmt.Sprintf("%#v", this.LabelValueCountByLabelName)+",\n") + } + if this.MemoryInBytesByLabelName != nil { + s = append(s, "MemoryInBytesByLabelName: "+fmt.Sprintf("%#v", this.MemoryInBytesByLabelName)+",\n") + } + if this.SeriesCountByLabelValuePair != nil { + s = append(s, "SeriesCountByLabelValuePair: "+fmt.Sprintf("%#v", this.SeriesCountByLabelValuePair)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} +func (this *TSDBStatItem) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 6) + s = append(s, "&client.TSDBStatItem{") + s = append(s, "Name: "+fmt.Sprintf("%#v", this.Name)+",\n") + s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} func valueToGoStringIngester(v interface{}, typ string) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -2838,6 +3210,7 @@ type IngesterClient interface { MetricsForLabelMatchers(ctx context.Context, in *MetricsForLabelMatchersRequest, opts ...grpc.CallOption) (*MetricsForLabelMatchersResponse, error) MetricsForLabelMatchersStream(ctx context.Context, in *MetricsForLabelMatchersRequest, opts ...grpc.CallOption) (Ingester_MetricsForLabelMatchersStreamClient, error) MetricsMetadata(ctx context.Context, in *MetricsMetadataRequest, opts ...grpc.CallOption) (*MetricsMetadataResponse, error) + TSDBStatus(ctx context.Context, in *TSDBStatusRequest, opts ...grpc.CallOption) (*TSDBStatusResponse, error) } type ingesterClient struct { @@ -3079,6 +3452,15 @@ func (c *ingesterClient) MetricsMetadata(ctx context.Context, in *MetricsMetadat return out, nil } +func (c *ingesterClient) TSDBStatus(ctx context.Context, in *TSDBStatusRequest, opts ...grpc.CallOption) (*TSDBStatusResponse, error) { + out := new(TSDBStatusResponse) + err := c.cc.Invoke(ctx, "/cortex.Ingester/TSDBStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // IngesterServer is the server API for Ingester service. type IngesterServer interface { Push(context.Context, *cortexpb.WriteRequest) (*cortexpb.WriteResponse, error) @@ -3094,6 +3476,7 @@ type IngesterServer interface { MetricsForLabelMatchers(context.Context, *MetricsForLabelMatchersRequest) (*MetricsForLabelMatchersResponse, error) MetricsForLabelMatchersStream(*MetricsForLabelMatchersRequest, Ingester_MetricsForLabelMatchersStreamServer) error MetricsMetadata(context.Context, *MetricsMetadataRequest) (*MetricsMetadataResponse, error) + TSDBStatus(context.Context, *TSDBStatusRequest) (*TSDBStatusResponse, error) } // UnimplementedIngesterServer can be embedded to have forward compatible implementations. @@ -3139,6 +3522,9 @@ func (*UnimplementedIngesterServer) MetricsForLabelMatchersStream(req *MetricsFo func (*UnimplementedIngesterServer) MetricsMetadata(ctx context.Context, req *MetricsMetadataRequest) (*MetricsMetadataResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method MetricsMetadata not implemented") } +func (*UnimplementedIngesterServer) TSDBStatus(ctx context.Context, req *TSDBStatusRequest) (*TSDBStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TSDBStatus not implemented") +} func RegisterIngesterServer(s *grpc.Server, srv IngesterServer) { s.RegisterService(&_Ingester_serviceDesc, srv) @@ -3398,13 +3784,31 @@ func _Ingester_MetricsMetadata_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -var _Ingester_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cortex.Ingester", - HandlerType: (*IngesterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Push", - Handler: _Ingester_Push_Handler, +func _Ingester_TSDBStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TSDBStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IngesterServer).TSDBStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cortex.Ingester/TSDBStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IngesterServer).TSDBStatus(ctx, req.(*TSDBStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Ingester_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cortex.Ingester", + HandlerType: (*IngesterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Push", + Handler: _Ingester_Push_Handler, }, { MethodName: "QueryExemplars", @@ -3434,6 +3838,10 @@ var _Ingester_serviceDesc = grpc.ServiceDesc{ MethodName: "MetricsMetadata", Handler: _Ingester_MetricsMetadata_Handler, }, + { + MethodName: "TSDBStatus", + Handler: _Ingester_TSDBStatus_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -4593,6 +5001,168 @@ func (m *TimeSeriesFile) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TSDBStatusRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TSDBStatusRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TSDBStatusRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Limit != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TSDBStatusResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TSDBStatusResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TSDBStatusResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SeriesCountByLabelValuePair) > 0 { + for iNdEx := len(m.SeriesCountByLabelValuePair) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SeriesCountByLabelValuePair[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.MemoryInBytesByLabelName) > 0 { + for iNdEx := len(m.MemoryInBytesByLabelName) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MemoryInBytesByLabelName[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if len(m.LabelValueCountByLabelName) > 0 { + for iNdEx := len(m.LabelValueCountByLabelName) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.LabelValueCountByLabelName[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.SeriesCountByMetricName) > 0 { + for iNdEx := len(m.SeriesCountByMetricName) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SeriesCountByMetricName[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIngester(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if m.NumLabelPairs != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.NumLabelPairs)) + i-- + dAtA[i] = 0x20 + } + if m.MaxTime != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.MaxTime)) + i-- + dAtA[i] = 0x18 + } + if m.MinTime != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.MinTime)) + i-- + dAtA[i] = 0x10 + } + if m.NumSeries != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.NumSeries)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TSDBStatItem) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TSDBStatItem) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TSDBStatItem) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != 0 { + i = encodeVarintIngester(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintIngester(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintIngester(dAtA []byte, offset int, v uint64) int { offset -= sovIngester(v) base := offset @@ -5098,6 +5668,79 @@ func (m *TimeSeriesFile) Size() (n int) { return n } +func (m *TSDBStatusRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Limit != 0 { + n += 1 + sovIngester(uint64(m.Limit)) + } + return n +} + +func (m *TSDBStatusResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NumSeries != 0 { + n += 1 + sovIngester(uint64(m.NumSeries)) + } + if m.MinTime != 0 { + n += 1 + sovIngester(uint64(m.MinTime)) + } + if m.MaxTime != 0 { + n += 1 + sovIngester(uint64(m.MaxTime)) + } + if m.NumLabelPairs != 0 { + n += 1 + sovIngester(uint64(m.NumLabelPairs)) + } + if len(m.SeriesCountByMetricName) > 0 { + for _, e := range m.SeriesCountByMetricName { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + if len(m.LabelValueCountByLabelName) > 0 { + for _, e := range m.LabelValueCountByLabelName { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + if len(m.MemoryInBytesByLabelName) > 0 { + for _, e := range m.MemoryInBytesByLabelName { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + if len(m.SeriesCountByLabelValuePair) > 0 { + for _, e := range m.SeriesCountByLabelValuePair { + l = e.Size() + n += 1 + l + sovIngester(uint64(l)) + } + } + return n +} + +func (m *TSDBStatItem) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovIngester(uint64(l)) + } + if m.Value != 0 { + n += 1 + sovIngester(uint64(m.Value)) + } + return n +} + func sovIngester(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -5477,6 +6120,64 @@ func (this *TimeSeriesFile) String() string { }, "") return s } +func (this *TSDBStatusRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TSDBStatusRequest{`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `}`, + }, "") + return s +} +func (this *TSDBStatusResponse) String() string { + if this == nil { + return "nil" + } + repeatedStringForSeriesCountByMetricName := "[]*TSDBStatItem{" + for _, f := range this.SeriesCountByMetricName { + repeatedStringForSeriesCountByMetricName += strings.Replace(f.String(), "TSDBStatItem", "TSDBStatItem", 1) + "," + } + repeatedStringForSeriesCountByMetricName += "}" + repeatedStringForLabelValueCountByLabelName := "[]*TSDBStatItem{" + for _, f := range this.LabelValueCountByLabelName { + repeatedStringForLabelValueCountByLabelName += strings.Replace(f.String(), "TSDBStatItem", "TSDBStatItem", 1) + "," + } + repeatedStringForLabelValueCountByLabelName += "}" + repeatedStringForMemoryInBytesByLabelName := "[]*TSDBStatItem{" + for _, f := range this.MemoryInBytesByLabelName { + repeatedStringForMemoryInBytesByLabelName += strings.Replace(f.String(), "TSDBStatItem", "TSDBStatItem", 1) + "," + } + repeatedStringForMemoryInBytesByLabelName += "}" + repeatedStringForSeriesCountByLabelValuePair := "[]*TSDBStatItem{" + for _, f := range this.SeriesCountByLabelValuePair { + repeatedStringForSeriesCountByLabelValuePair += strings.Replace(f.String(), "TSDBStatItem", "TSDBStatItem", 1) + "," + } + repeatedStringForSeriesCountByLabelValuePair += "}" + s := strings.Join([]string{`&TSDBStatusResponse{`, + `NumSeries:` + fmt.Sprintf("%v", this.NumSeries) + `,`, + `MinTime:` + fmt.Sprintf("%v", this.MinTime) + `,`, + `MaxTime:` + fmt.Sprintf("%v", this.MaxTime) + `,`, + `NumLabelPairs:` + fmt.Sprintf("%v", this.NumLabelPairs) + `,`, + `SeriesCountByMetricName:` + repeatedStringForSeriesCountByMetricName + `,`, + `LabelValueCountByLabelName:` + repeatedStringForLabelValueCountByLabelName + `,`, + `MemoryInBytesByLabelName:` + repeatedStringForMemoryInBytesByLabelName + `,`, + `SeriesCountByLabelValuePair:` + repeatedStringForSeriesCountByLabelValuePair + `,`, + `}`, + }, "") + return s +} +func (this *TSDBStatItem) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TSDBStatItem{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Value:` + fmt.Sprintf("%v", this.Value) + `,`, + `}`, + }, "") + return s +} func valueToStringIngester(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -8534,6 +9235,447 @@ func (m *TimeSeriesFile) Unmarshal(dAtA []byte) error { } return nil } +func (m *TSDBStatusRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TSDBStatusRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TSDBStatusRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipIngester(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TSDBStatusResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TSDBStatusResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TSDBStatusResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumSeries", wireType) + } + m.NumSeries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumSeries |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinTime", wireType) + } + m.MinTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTime", wireType) + } + m.MaxTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumLabelPairs", wireType) + } + m.NumLabelPairs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumLabelPairs |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeriesCountByMetricName", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeriesCountByMetricName = append(m.SeriesCountByMetricName, &TSDBStatItem{}) + if err := m.SeriesCountByMetricName[len(m.SeriesCountByMetricName)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelValueCountByLabelName", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelValueCountByLabelName = append(m.LabelValueCountByLabelName, &TSDBStatItem{}) + if err := m.LabelValueCountByLabelName[len(m.LabelValueCountByLabelName)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MemoryInBytesByLabelName", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MemoryInBytesByLabelName = append(m.MemoryInBytesByLabelName, &TSDBStatItem{}) + if err := m.MemoryInBytesByLabelName[len(m.MemoryInBytesByLabelName)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeriesCountByLabelValuePair", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeriesCountByLabelValuePair = append(m.SeriesCountByLabelValuePair, &TSDBStatItem{}) + if err := m.SeriesCountByLabelValuePair[len(m.SeriesCountByLabelValuePair)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIngester(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TSDBStatItem) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TSDBStatItem: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TSDBStatItem: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthIngester + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIngester + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIngester + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipIngester(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthIngester + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipIngester(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pkg/ingester/client/ingester.proto b/pkg/ingester/client/ingester.proto index 9a42ebfb3d6..68ef109f6c6 100644 --- a/pkg/ingester/client/ingester.proto +++ b/pkg/ingester/client/ingester.proto @@ -26,6 +26,7 @@ service Ingester { rpc MetricsForLabelMatchers(MetricsForLabelMatchersRequest) returns (MetricsForLabelMatchersResponse) {}; rpc MetricsForLabelMatchersStream(MetricsForLabelMatchersRequest) returns (stream MetricsForLabelMatchersStreamResponse) {}; rpc MetricsMetadata(MetricsMetadataRequest) returns (MetricsMetadataResponse) {}; + rpc TSDBStatus(TSDBStatusRequest) returns (TSDBStatusResponse) {}; } message ReadRequest { @@ -177,3 +178,23 @@ message TimeSeriesFile { string filename = 3; bytes data = 4; } + +message TSDBStatusRequest { + int32 limit = 1; +} + +message TSDBStatusResponse { + uint64 num_series = 1; + int64 min_time = 2; + int64 max_time = 3; + int32 num_label_pairs = 4; + repeated TSDBStatItem series_count_by_metric_name = 5; + repeated TSDBStatItem label_value_count_by_label_name = 6; + repeated TSDBStatItem memory_in_bytes_by_label_name = 7; + repeated TSDBStatItem series_count_by_label_value_pair = 8; +} + +message TSDBStatItem { + string name = 1; + uint64 value = 2; +} diff --git a/pkg/ingester/ingester.go b/pkg/ingester/ingester.go index 59f2abd09ed..078cc79b418 100644 --- a/pkg/ingester/ingester.go +++ b/pkg/ingester/ingester.go @@ -34,6 +34,7 @@ import ( "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/prometheus/prometheus/tsdb/chunks" + "github.com/prometheus/prometheus/tsdb/index" "github.com/prometheus/prometheus/util/compression" "github.com/prometheus/prometheus/util/zeropool" "github.com/thanos-io/objstore" @@ -2300,6 +2301,57 @@ func (i *Ingester) UserStats(ctx context.Context, req *client.UserStatsRequest) }, nil } +// TSDBStatus returns TSDB cardinality statistics for the tenant's TSDB head. +func (i *Ingester) TSDBStatus(ctx context.Context, req *client.TSDBStatusRequest) (*client.TSDBStatusResponse, error) { + if err := i.checkRunning(); err != nil { + return nil, err + } + + userID, err := users.TenantID(ctx) + if err != nil { + return nil, err + } + + db, err := i.getTSDB(userID) + if err != nil || db == nil { + return &client.TSDBStatusResponse{}, nil + } + + limit := int(req.Limit) + if limit <= 0 { + limit = 10 + } + + stats := db.Head().Stats(labels.MetricName, limit) + + resp := &client.TSDBStatusResponse{ + NumSeries: stats.NumSeries, + MinTime: stats.MinTime, + MaxTime: stats.MaxTime, + } + + if stats.IndexPostingStats != nil { + resp.NumLabelPairs = int32(stats.IndexPostingStats.NumLabelPairs) + resp.SeriesCountByMetricName = statsToPB(stats.IndexPostingStats.CardinalityMetricsStats) + resp.LabelValueCountByLabelName = statsToPB(stats.IndexPostingStats.CardinalityLabelStats) + resp.MemoryInBytesByLabelName = statsToPB(stats.IndexPostingStats.LabelValueStats) + resp.SeriesCountByLabelValuePair = statsToPB(stats.IndexPostingStats.LabelValuePairsStats) + } + + return resp, nil +} + +func statsToPB(stats []index.Stat) []*client.TSDBStatItem { + items := make([]*client.TSDBStatItem, len(stats)) + for i, s := range stats { + items[i] = &client.TSDBStatItem{ + Name: s.Name, + Value: s.Count, + } + } + return items +} + func (i *Ingester) userStats() []UserIDStats { i.stoppedMtx.RLock() defer i.stoppedMtx.RUnlock() diff --git a/pkg/ingester/ingester_test.go b/pkg/ingester/ingester_test.go index 8f09aab9876..5f6bba34deb 100644 --- a/pkg/ingester/ingester_test.go +++ b/pkg/ingester/ingester_test.go @@ -5381,6 +5381,67 @@ func Test_Ingester_UserStats(t *testing.T) { assert.Equal(t, uint64(3), res.NumSeries) } +func Test_Ingester_TSDBStatus(t *testing.T) { + series := []struct { + lbls labels.Labels + value float64 + timestamp int64 + }{ + {labels.Labels{{Name: labels.MetricName, Value: "test_1"}, {Name: "route", Value: "get_user"}, {Name: "status", Value: "200"}}, 1, 100000}, + {labels.Labels{{Name: labels.MetricName, Value: "test_1"}, {Name: "route", Value: "get_user"}, {Name: "status", Value: "500"}}, 1, 110000}, + {labels.Labels{{Name: labels.MetricName, Value: "test_2"}}, 2, 200000}, + } + + // Create ingester + i, err := prepareIngesterWithBlocksStorage(t, defaultIngesterTestConfig(t), prometheus.NewRegistry()) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(context.Background(), i)) + defer services.StopAndAwaitTerminated(context.Background(), i) //nolint:errcheck + + // Wait until it's ACTIVE + test.Poll(t, 1*time.Second, ring.ACTIVE, func() interface{} { + return i.lifecycler.GetState() + }) + + // Push series + ctx := user.InjectOrgID(context.Background(), "test") + + for _, series := range series { + req, _ := mockWriteRequest(t, series.lbls, series.value, series.timestamp) + _, err := i.Push(ctx, req) + require.NoError(t, err) + } + + // Get TSDB status + res, err := i.TSDBStatus(ctx, &client.TSDBStatusRequest{Limit: 10}) + require.NoError(t, err) + + assert.Equal(t, uint64(3), res.NumSeries) + assert.True(t, res.MinTime > 0) + assert.True(t, res.MaxTime > 0) + assert.True(t, res.MaxTime >= res.MinTime) + + // Should have top metrics by series count + require.NotEmpty(t, res.SeriesCountByMetricName) + // test_1 has 2 series, test_2 has 1 + assert.Equal(t, "test_1", res.SeriesCountByMetricName[0].Name) + assert.Equal(t, uint64(2), res.SeriesCountByMetricName[0].Value) + + // Label value counts should be present + require.NotEmpty(t, res.LabelValueCountByLabelName) + + // Test default limit when 0 + res2, err := i.TSDBStatus(ctx, &client.TSDBStatusRequest{Limit: 0}) + require.NoError(t, err) + assert.Equal(t, uint64(3), res2.NumSeries) + + // Test with non-existent tenant + ctxOther := user.InjectOrgID(context.Background(), "nonexistent") + res3, err := i.TSDBStatus(ctxOther, &client.TSDBStatusRequest{Limit: 10}) + require.NoError(t, err) + assert.Equal(t, uint64(0), res3.NumSeries) +} + func Test_Ingester_AllUserStats(t *testing.T) { series := []struct { user string From c2c14b785746d0c3e474304fa448c46b6275cafa Mon Sep 17 00:00:00 2001 From: Charlie Le Date: Thu, 5 Mar 2026 15:49:51 -0800 Subject: [PATCH 2/3] Add API documentation for /api/v1/status/tsdb endpoint Document the new TSDB cardinality status endpoint in the HTTP API reference, including query parameters, example request/response, and field descriptions. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Charlie Le --- docs/api/_index.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/api/_index.md b/docs/api/_index.md index 356a5e82313..cc29f84e0ac 100644 --- a/docs/api/_index.md +++ b/docs/api/_index.md @@ -46,6 +46,7 @@ For the sake of clarity, in this document we have grouped API endpoints by servi | [Remote read](#remote-read) | Querier, Query-frontend || `POST /api/v1/read` | | [Build information](#build-information) | Querier, Query-frontend |v1.15.0| `GET /api/v1/status/buildinfo` | | [Get tenant ingestion stats](#get-tenant-ingestion-stats) | Querier || `GET /api/v1/user_stats` | +| [Get tenant TSDB status](#get-tenant-tsdb-status) | Querier || `GET /api/v1/status/tsdb` | | [Ruler ring status](#ruler-ring-status) | Ruler || `GET /ruler/ring` | | [Ruler rules ](#ruler-rule-groups) | Ruler || `GET /ruler/rule_groups` | | [List rules](#list-rules) | Ruler || `GET /api/v1/rules` | @@ -505,6 +506,67 @@ Returns realtime ingestion rate, for the authenticated tenant, in `JSON` format. _Requires [authentication](#authentication)._ +### Get tenant TSDB status + +``` +GET /api/v1/status/tsdb + +# Legacy +GET /api/v1/status/tsdb +``` + +Returns TSDB cardinality statistics for the authenticated tenant's in-memory (head) data, in `JSON` format. This is useful for understanding which metrics, labels, and label-value pairs contribute the most series and for debugging high-cardinality issues. + +The endpoint accepts an optional `limit` query parameter (default `10`) that controls how many entries are returned in each top-N list. + +_Requires [authentication](#authentication)._ + +#### Example request + +``` +GET /api/v1/status/tsdb?limit=5 +``` + +#### Example response + +```json +{ + "numSeries": 1234, + "minTime": 1709640000000, + "maxTime": 1709726400000, + "numLabelPairs": 42, + "seriesCountByMetricName": [ + { "name": "http_requests_total", "value": 500 }, + { "name": "process_cpu_seconds_total", "value": 200 } + ], + "labelValueCountByLabelName": [ + { "name": "instance", "value": 150 }, + { "name": "job", "value": 10 } + ], + "memoryInBytesByLabelName": [ + { "name": "instance", "value": 32000 }, + { "name": "job", "value": 4800 } + ], + "seriesCountByLabelValuePair": [ + { "name": "job=cortex", "value": 800 }, + { "name": "job=prometheus", "value": 300 } + ] +} +``` + +#### Response fields + +| Field | Description | +|-------|-------------| +| `numSeries` | Total number of active series for the tenant. | +| `minTime` | Minimum timestamp (ms) across all samples in the TSDB head. | +| `maxTime` | Maximum timestamp (ms) across all samples in the TSDB head. | +| `numLabelPairs` | Total number of distinct label name-value pairs. | +| `seriesCountByMetricName` | Top metrics ranked by number of series (descending). | +| `labelValueCountByLabelName` | Top label names ranked by number of unique values (descending). | +| `memoryInBytesByLabelName` | Top label names ranked by estimated memory usage in bytes (descending). | +| `seriesCountByLabelValuePair` | Top label name=value pairs ranked by number of series (descending). | + ## Ruler The ruler API endpoints require to configure a backend object storage to store the recording rules and alerts. The ruler API uses the concept of a "namespace" when creating rule groups. This is a stand in for the name of the rule file in Prometheus and rule groups must be named uniquely within a namespace. From 2536082ffd699b3ad1f2ef2f617ebe87ad3a4d6b Mon Sep 17 00:00:00 2001 From: Charlie Le Date: Thu, 5 Mar 2026 18:20:21 -0800 Subject: [PATCH 3/3] Add integration tests for /api/v1/status/tsdb endpoint End-to-end test that starts a single-binary Cortex cluster, pushes series with varying cardinality, and validates the TSDB status API returns correct series counts, metric name breakdowns, and limit truncation. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Charlie Le --- integration/api_endpoints_test.go | 65 +++++++++++++++++++++++++++++++ integration/e2ecortex/client.go | 35 +++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/integration/api_endpoints_test.go b/integration/api_endpoints_test.go index ddcfada4f04..6f66f5c7ecf 100644 --- a/integration/api_endpoints_test.go +++ b/integration/api_endpoints_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/prompb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/thanos-io/thanos/pkg/runutil" @@ -134,3 +135,67 @@ func Test_AllUserStats_WhenIngesterRollingUpdate(t *testing.T) { require.Len(t, userStats, 1) require.Equal(t, uint64(2), userStats[0].QueriedIngesters) } + +func TestTSDBStatus(t *testing.T) { + s, err := e2e.NewScenario(networkName) + require.NoError(t, err) + defer s.Close() + + flags := BlocksStorageFlags() + flags["-distributor.replication-factor"] = "1" + + // Start dependencies. + consul := e2edb.NewConsul() + minio := e2edb.NewMinio(9000, flags["-blocks-storage.s3.bucket-name"]) + require.NoError(t, s.StartAndWaitReady(consul, minio)) + + // Start Cortex in single binary mode. + cortex := e2ecortex.NewSingleBinary("cortex-1", flags, "") + require.NoError(t, s.StartAndWaitReady(cortex)) + + // Wait until the ingester ring is active. + require.NoError(t, cortex.WaitSumMetricsWithOptions(e2e.Equals(1), []string{"cortex_ring_members"}, e2e.WithLabelMatchers( + labels.MustNewMatcher(labels.MatchEqual, "name", "ingester"), + labels.MustNewMatcher(labels.MatchEqual, "state", "ACTIVE")))) + + client, err := e2ecortex.NewClient(cortex.HTTPEndpoint(), cortex.HTTPEndpoint(), "", "", "test-tenant") + require.NoError(t, err) + + now := time.Now() + + // Push multiple series to create interesting cardinality: + // - http_requests_total with 3 label combinations + // - process_cpu_seconds_total with 1 label combination + series1, _ := generateSeries("http_requests_total", now, prompb.Label{Name: "method", Value: "GET"}, prompb.Label{Name: "status", Value: "200"}) + series2, _ := generateSeries("http_requests_total", now, prompb.Label{Name: "method", Value: "POST"}, prompb.Label{Name: "status", Value: "200"}) + series3, _ := generateSeries("http_requests_total", now, prompb.Label{Name: "method", Value: "GET"}, prompb.Label{Name: "status", Value: "500"}) + series4, _ := generateSeries("process_cpu_seconds_total", now, prompb.Label{Name: "instance", Value: "a"}) + + allSeries := append(series1, series2...) + allSeries = append(allSeries, series3...) + allSeries = append(allSeries, series4...) + + res, err := client.Push(allSeries) + require.NoError(t, err) + require.Equal(t, 200, res.StatusCode) + + // Query TSDB status with default limit. + status, err := client.TSDBStatus(10) + require.NoError(t, err) + + assert.Equal(t, uint64(4), status.NumSeries) + require.GreaterOrEqual(t, len(status.SeriesCountByMetricName), 2) + assert.Equal(t, "http_requests_total", status.SeriesCountByMetricName[0].Name) + assert.Equal(t, uint64(3), status.SeriesCountByMetricName[0].Value) + assert.Equal(t, "process_cpu_seconds_total", status.SeriesCountByMetricName[1].Name) + assert.Equal(t, uint64(1), status.SeriesCountByMetricName[1].Value) + assert.NotEmpty(t, status.LabelValueCountByLabelName) + assert.Greater(t, status.MinTime, int64(0)) + assert.Greater(t, status.MaxTime, int64(0)) + + // Query TSDB status with limit=1 to verify truncation. + status, err = client.TSDBStatus(1) + require.NoError(t, err) + assert.Len(t, status.SeriesCountByMetricName, 1) + assert.Equal(t, "http_requests_total", status.SeriesCountByMetricName[0].Name) +} diff --git a/integration/e2ecortex/client.go b/integration/e2ecortex/client.go index 73f3c6bbf32..60b02cf4a92 100644 --- a/integration/e2ecortex/client.go +++ b/integration/e2ecortex/client.go @@ -34,6 +34,7 @@ import ( "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" + "github.com/cortexproject/cortex/pkg/distributor" "github.com/cortexproject/cortex/pkg/ingester" "github.com/cortexproject/cortex/pkg/ruler" "github.com/cortexproject/cortex/pkg/util/backoff" @@ -164,6 +165,40 @@ func (c *Client) AllUserStats() ([]ingester.UserIDStats, error) { return userStats, nil } +func (c *Client) TSDBStatus(limit int) (*distributor.TSDBStatusResult, error) { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1/status/tsdb?limit=%d", c.distributorAddress, limit), nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", "application/json") + req.Header.Set("X-Scope-OrgID", c.orgID) + + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + res, err := c.httpClient.Do(req.WithContext(ctx)) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + body, _ := io.ReadAll(res.Body) + return nil, fmt.Errorf("unexpected status code %d: %s", res.StatusCode, string(body)) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + + var result distributor.TSDBStatusResult + if err := json.Unmarshal(body, &result); err != nil { + return nil, err + } + + return &result, nil +} + // Push the input timeseries to the remote endpoint func (c *Client) Push(timeseries []prompb.TimeSeries, metadata ...prompb.MetricMetadata) (*http.Response, error) { // Create write request