mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Pass limit param as hint to storage.Querier
Signed-off-by: 🌲 Harry 🌊 John 🏔 <johrry@amazon.com>
This commit is contained in:
parent
f9ca6c4ae6
commit
d5f6887294
|
@ -256,7 +256,7 @@ URL query parameters:
|
||||||
series to return. At least one `match[]` argument must be provided.
|
series to return. At least one `match[]` argument must be provided.
|
||||||
- `start=<rfc3339 | unix_timestamp>`: Start timestamp.
|
- `start=<rfc3339 | unix_timestamp>`: Start timestamp.
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp.
|
||||||
- `limit=<number>`: Maximum number of returned series. Optional.
|
- `limit=<number>`: Maximum number of returned series. Optional. 0 means disabled.
|
||||||
|
|
||||||
You can URL-encode these parameters directly in the request body by using the `POST` method and
|
You can URL-encode these parameters directly in the request body by using the `POST` method and
|
||||||
`Content-Type: application/x-www-form-urlencoded` header. This is useful when specifying a large
|
`Content-Type: application/x-www-form-urlencoded` header. This is useful when specifying a large
|
||||||
|
@ -307,7 +307,7 @@ URL query parameters:
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
||||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||||
series from which to read the label names. Optional.
|
series from which to read the label names. Optional.
|
||||||
- `limit=<number>`: Maximum number of returned series. Optional.
|
- `limit=<number>`: Maximum number of returned series. Optional. 0 means disabled.
|
||||||
|
|
||||||
|
|
||||||
The `data` section of the JSON response is a list of string label names.
|
The `data` section of the JSON response is a list of string label names.
|
||||||
|
@ -358,7 +358,7 @@ URL query parameters:
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
||||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||||
series from which to read the label values. Optional.
|
series from which to read the label values. Optional.
|
||||||
- `limit=<number>`: Maximum number of returned series. Optional.
|
- `limit=<number>`: Maximum number of returned series. Optional. 0 means disabled.
|
||||||
|
|
||||||
|
|
||||||
The `data` section of the JSON response is a list of string label values.
|
The `data` section of the JSON response is a list of string label values.
|
||||||
|
|
|
@ -236,11 +236,11 @@ func (q *errQuerier) Select(context.Context, bool, *storage.SelectHints, ...*lab
|
||||||
return errSeriesSet{err: q.err}
|
return errSeriesSet{err: q.err}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*errQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (*errQuerier) LabelValues(context.Context, string, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*errQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (*errQuerier) LabelNames(context.Context, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
func (*errQuerier) Close() error { return nil }
|
func (*errQuerier) Close() error { return nil }
|
||||||
|
|
|
@ -236,11 +236,11 @@ func (errQuerier) Select(context.Context, bool, *storage.SelectHints, ...*labels
|
||||||
return storage.ErrSeriesSet(errSelect)
|
return storage.ErrSeriesSet(errSelect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (errQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (errQuerier) LabelValues(context.Context, string, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, errors.New("label values error")
|
return nil, nil, errors.New("label values error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (errQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (errQuerier) LabelNames(context.Context, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, errors.New("label names error")
|
return nil, nil, errors.New("label names error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,11 +122,11 @@ type MockQuerier struct {
|
||||||
SelectMockFunction func(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) SeriesSet
|
SelectMockFunction func(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) SeriesSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *MockQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *MockQuerier) LabelValues(context.Context, string, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *MockQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *MockQuerier) LabelNames(context.Context, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,12 +161,12 @@ type LabelQuerier interface {
|
||||||
// It is not safe to use the strings beyond the lifetime of the querier.
|
// It is not safe to use the strings beyond the lifetime of the querier.
|
||||||
// If matchers are specified the returned result set is reduced
|
// If matchers are specified the returned result set is reduced
|
||||||
// to label values of metrics matching the matchers.
|
// to label values of metrics matching the matchers.
|
||||||
LabelValues(ctx context.Context, name string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error)
|
LabelValues(ctx context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error)
|
||||||
|
|
||||||
// LabelNames returns all the unique label names present in the block in sorted order.
|
// LabelNames returns all the unique label names present in the block in sorted order.
|
||||||
// If matchers are specified the returned result set is reduced
|
// If matchers are specified the returned result set is reduced
|
||||||
// to label names of metrics matching the matchers.
|
// to label names of metrics matching the matchers.
|
||||||
LabelNames(ctx context.Context, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error)
|
LabelNames(ctx context.Context, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error)
|
||||||
|
|
||||||
// Close releases the resources of the Querier.
|
// Close releases the resources of the Querier.
|
||||||
Close() error
|
Close() error
|
||||||
|
@ -190,6 +190,9 @@ type SelectHints struct {
|
||||||
Start int64 // Start time in milliseconds for this select.
|
Start int64 // Start time in milliseconds for this select.
|
||||||
End int64 // End time in milliseconds for this select.
|
End int64 // End time in milliseconds for this select.
|
||||||
|
|
||||||
|
// Maximum number of results returned. Use a value of 0 to disable.
|
||||||
|
Limit int
|
||||||
|
|
||||||
Step int64 // Query step size in milliseconds.
|
Step int64 // Query step size in milliseconds.
|
||||||
Func string // String representation of surrounding function or aggregation.
|
Func string // String representation of surrounding function or aggregation.
|
||||||
|
|
||||||
|
@ -217,6 +220,13 @@ type SelectHints struct {
|
||||||
DisableTrimming bool
|
DisableTrimming bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LabelHints specifies hints passed for label reads.
|
||||||
|
// This is used only as an option for implementation to use.
|
||||||
|
type LabelHints struct {
|
||||||
|
// Maximum number of results returned. Use a value of 0 to disable.
|
||||||
|
Limit int
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(bwplotka): Move to promql/engine_test.go?
|
// TODO(bwplotka): Move to promql/engine_test.go?
|
||||||
// QueryableFunc is an adapter to allow the use of ordinary functions as
|
// QueryableFunc is an adapter to allow the use of ordinary functions as
|
||||||
// Queryables. It follows the idea of http.HandlerFunc.
|
// Queryables. It follows the idea of http.HandlerFunc.
|
||||||
|
|
|
@ -161,8 +161,8 @@ func (l labelGenericQueriers) SplitByHalf() (labelGenericQueriers, labelGenericQ
|
||||||
// LabelValues returns all potential values for a label name.
|
// LabelValues returns all potential values for a label name.
|
||||||
// If matchers are specified the returned result set is reduced
|
// If matchers are specified the returned result set is reduced
|
||||||
// to label values of metrics matching the matchers.
|
// to label values of metrics matching the matchers.
|
||||||
func (q *mergeGenericQuerier) LabelValues(ctx context.Context, name string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *mergeGenericQuerier) LabelValues(ctx context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
res, ws, err := q.lvals(ctx, q.queriers, name, matchers...)
|
res, ws, err := q.lvals(ctx, q.queriers, name, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("LabelValues() from merge generic querier for label %s: %w", name, err)
|
return nil, nil, fmt.Errorf("LabelValues() from merge generic querier for label %s: %w", name, err)
|
||||||
}
|
}
|
||||||
|
@ -170,22 +170,22 @@ func (q *mergeGenericQuerier) LabelValues(ctx context.Context, name string, matc
|
||||||
}
|
}
|
||||||
|
|
||||||
// lvals performs merge sort for LabelValues from multiple queriers.
|
// lvals performs merge sort for LabelValues from multiple queriers.
|
||||||
func (q *mergeGenericQuerier) lvals(ctx context.Context, lq labelGenericQueriers, n string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *mergeGenericQuerier) lvals(ctx context.Context, lq labelGenericQueriers, n string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
if lq.Len() == 0 {
|
if lq.Len() == 0 {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
if lq.Len() == 1 {
|
if lq.Len() == 1 {
|
||||||
return lq.Get(0).LabelValues(ctx, n, matchers...)
|
return lq.Get(0).LabelValues(ctx, n, hints, matchers...)
|
||||||
}
|
}
|
||||||
a, b := lq.SplitByHalf()
|
a, b := lq.SplitByHalf()
|
||||||
|
|
||||||
var ws annotations.Annotations
|
var ws annotations.Annotations
|
||||||
s1, w, err := q.lvals(ctx, a, n, matchers...)
|
s1, w, err := q.lvals(ctx, a, n, hints, matchers...)
|
||||||
ws.Merge(w)
|
ws.Merge(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ws, err
|
return nil, ws, err
|
||||||
}
|
}
|
||||||
s2, ws, err := q.lvals(ctx, b, n, matchers...)
|
s2, ws, err := q.lvals(ctx, b, n, hints, matchers...)
|
||||||
ws.Merge(w)
|
ws.Merge(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ws, err
|
return nil, ws, err
|
||||||
|
@ -221,13 +221,13 @@ func mergeStrings(a, b []string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelNames returns all the unique label names present in all queriers in sorted order.
|
// LabelNames returns all the unique label names present in all queriers in sorted order.
|
||||||
func (q *mergeGenericQuerier) LabelNames(ctx context.Context, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *mergeGenericQuerier) LabelNames(ctx context.Context, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
var (
|
var (
|
||||||
labelNamesMap = make(map[string]struct{})
|
labelNamesMap = make(map[string]struct{})
|
||||||
warnings annotations.Annotations
|
warnings annotations.Annotations
|
||||||
)
|
)
|
||||||
for _, querier := range q.queriers {
|
for _, querier := range q.queriers {
|
||||||
names, wrn, err := querier.LabelNames(ctx, matchers...)
|
names, wrn, err := querier.LabelNames(ctx, hints, matchers...)
|
||||||
if wrn != nil {
|
if wrn != nil {
|
||||||
// TODO(bwplotka): We could potentially wrap warnings.
|
// TODO(bwplotka): We could potentially wrap warnings.
|
||||||
warnings.Merge(wrn)
|
warnings.Merge(wrn)
|
||||||
|
|
|
@ -1361,7 +1361,7 @@ func (m *mockGenericQuerier) Select(_ context.Context, b bool, _ *SelectHints, _
|
||||||
return &mockGenericSeriesSet{resp: m.resp, warnings: m.warnings, err: m.err}
|
return &mockGenericSeriesSet{resp: m.resp, warnings: m.warnings, err: m.err}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGenericQuerier) LabelValues(_ context.Context, name string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (m *mockGenericQuerier) LabelValues(_ context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
m.mtx.Lock()
|
m.mtx.Lock()
|
||||||
m.labelNamesRequested = append(m.labelNamesRequested, labelNameRequest{
|
m.labelNamesRequested = append(m.labelNamesRequested, labelNameRequest{
|
||||||
name: name,
|
name: name,
|
||||||
|
@ -1371,7 +1371,7 @@ func (m *mockGenericQuerier) LabelValues(_ context.Context, name string, matcher
|
||||||
return m.resp, m.warnings, m.err
|
return m.resp, m.warnings, m.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockGenericQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (m *mockGenericQuerier) LabelNames(context.Context, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
m.mtx.Lock()
|
m.mtx.Lock()
|
||||||
m.labelNamesCalls++
|
m.labelNamesCalls++
|
||||||
m.mtx.Unlock()
|
m.mtx.Unlock()
|
||||||
|
@ -1560,7 +1560,7 @@ func TestMergeGenericQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("LabelNames", func(t *testing.T) {
|
t.Run("LabelNames", func(t *testing.T) {
|
||||||
res, w, err := q.LabelNames(ctx)
|
res, w, err := q.LabelNames(ctx, nil)
|
||||||
require.Subset(t, tcase.expectedWarnings, w)
|
require.Subset(t, tcase.expectedWarnings, w)
|
||||||
require.ErrorIs(t, err, tcase.expectedErrs[1], "expected error doesn't match")
|
require.ErrorIs(t, err, tcase.expectedErrs[1], "expected error doesn't match")
|
||||||
require.Equal(t, tcase.expectedLabels, res)
|
require.Equal(t, tcase.expectedLabels, res)
|
||||||
|
@ -1575,7 +1575,7 @@ func TestMergeGenericQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("LabelValues", func(t *testing.T) {
|
t.Run("LabelValues", func(t *testing.T) {
|
||||||
res, w, err := q.LabelValues(ctx, "test")
|
res, w, err := q.LabelValues(ctx, "test", nil)
|
||||||
require.Subset(t, tcase.expectedWarnings, w)
|
require.Subset(t, tcase.expectedWarnings, w)
|
||||||
require.ErrorIs(t, err, tcase.expectedErrs[2], "expected error doesn't match")
|
require.ErrorIs(t, err, tcase.expectedErrs[2], "expected error doesn't match")
|
||||||
require.Equal(t, tcase.expectedLabels, res)
|
require.Equal(t, tcase.expectedLabels, res)
|
||||||
|
@ -1591,7 +1591,7 @@ func TestMergeGenericQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("LabelValuesWithMatchers", func(t *testing.T) {
|
t.Run("LabelValuesWithMatchers", func(t *testing.T) {
|
||||||
matcher := labels.MustNewMatcher(labels.MatchEqual, "otherLabel", "someValue")
|
matcher := labels.MustNewMatcher(labels.MatchEqual, "otherLabel", "someValue")
|
||||||
res, w, err := q.LabelValues(ctx, "test2", matcher)
|
res, w, err := q.LabelValues(ctx, "test2", nil, matcher)
|
||||||
require.Subset(t, tcase.expectedWarnings, w)
|
require.Subset(t, tcase.expectedWarnings, w)
|
||||||
require.ErrorIs(t, err, tcase.expectedErrs[3], "expected error doesn't match")
|
require.ErrorIs(t, err, tcase.expectedErrs[3], "expected error doesn't match")
|
||||||
require.Equal(t, tcase.expectedLabels, res)
|
require.Equal(t, tcase.expectedLabels, res)
|
||||||
|
|
|
@ -31,11 +31,11 @@ func (noopQuerier) Select(context.Context, bool, *SelectHints, ...*labels.Matche
|
||||||
return NoopSeriesSet()
|
return NoopSeriesSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (noopQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (noopQuerier) LabelValues(context.Context, string, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (noopQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (noopQuerier) LabelNames(context.Context, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ func (noopChunkQuerier) Select(context.Context, bool, *SelectHints, ...*labels.M
|
||||||
return NoopChunkedSeriesSet()
|
return NoopChunkedSeriesSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (noopChunkQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (noopChunkQuerier) LabelValues(context.Context, string, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (noopChunkQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (noopChunkQuerier) LabelNames(context.Context, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,13 +210,13 @@ func (q querier) addExternalLabels(ms []*labels.Matcher) ([]*labels.Matcher, []s
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelValues implements storage.Querier and is a noop.
|
// LabelValues implements storage.Querier and is a noop.
|
||||||
func (q *querier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *querier) LabelValues(context.Context, string, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
// TODO: Implement: https://github.com/prometheus/prometheus/issues/3351
|
// TODO: Implement: https://github.com/prometheus/prometheus/issues/3351
|
||||||
return nil, nil, errors.New("not implemented")
|
return nil, nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelNames implements storage.Querier and is a noop.
|
// LabelNames implements storage.Querier and is a noop.
|
||||||
func (q *querier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *querier) LabelNames(context.Context, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
// TODO: Implement: https://github.com/prometheus/prometheus/issues/3351
|
// TODO: Implement: https://github.com/prometheus/prometheus/issues/3351
|
||||||
return nil, nil, errors.New("not implemented")
|
return nil, nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,16 +49,16 @@ func newSecondaryQuerierFromChunk(cq ChunkQuerier) genericQuerier {
|
||||||
return &secondaryQuerier{genericQuerier: newGenericQuerierFromChunk(cq)}
|
return &secondaryQuerier{genericQuerier: newGenericQuerierFromChunk(cq)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *secondaryQuerier) LabelValues(ctx context.Context, name string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (s *secondaryQuerier) LabelValues(ctx context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
vals, w, err := s.genericQuerier.LabelValues(ctx, name, matchers...)
|
vals, w, err := s.genericQuerier.LabelValues(ctx, name, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, w.Add(err), nil
|
return nil, w.Add(err), nil
|
||||||
}
|
}
|
||||||
return vals, w, nil
|
return vals, w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *secondaryQuerier) LabelNames(ctx context.Context, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (s *secondaryQuerier) LabelNames(ctx context.Context, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
names, w, err := s.genericQuerier.LabelNames(ctx, matchers...)
|
names, w, err := s.genericQuerier.LabelNames(ctx, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, w.Add(err), nil
|
return nil, w.Add(err), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1001,7 +1001,7 @@ func TestWALFlushedOnDBClose(t *testing.T) {
|
||||||
q, err := db.Querier(0, 1)
|
q, err := db.Querier(0, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
values, ws, err := q.LabelValues(ctx, "labelname")
|
values, ws, err := q.LabelValues(ctx, "labelname", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, ws)
|
require.Empty(t, ws)
|
||||||
require.Equal(t, []string{"labelvalue"}, values)
|
require.Equal(t, []string{"labelvalue"}, values)
|
||||||
|
@ -1976,7 +1976,7 @@ func TestQuerierWithBoundaryChunks(t *testing.T) {
|
||||||
defer q.Close()
|
defer q.Close()
|
||||||
|
|
||||||
// The requested interval covers 2 blocks, so the querier's label values for blockID should give us 2 values, one from each block.
|
// The requested interval covers 2 blocks, so the querier's label values for blockID should give us 2 values, one from each block.
|
||||||
b, ws, err := q.LabelValues(ctx, "blockID")
|
b, ws, err := q.LabelValues(ctx, "blockID", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
var nilAnnotations annotations.Annotations
|
var nilAnnotations annotations.Annotations
|
||||||
require.Equal(t, nilAnnotations, ws)
|
require.Equal(t, nilAnnotations, ws)
|
||||||
|
@ -2288,7 +2288,7 @@ func TestDB_LabelNames(t *testing.T) {
|
||||||
q, err := db.Querier(math.MinInt64, math.MaxInt64)
|
q, err := db.Querier(math.MinInt64, math.MaxInt64)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
var ws annotations.Annotations
|
var ws annotations.Annotations
|
||||||
labelNames, ws, err = q.LabelNames(ctx)
|
labelNames, ws, err = q.LabelNames(ctx, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, ws)
|
require.Empty(t, ws)
|
||||||
require.NoError(t, q.Close())
|
require.NoError(t, q.Close())
|
||||||
|
|
|
@ -77,12 +77,12 @@ func newBlockBaseQuerier(b BlockReader, mint, maxt int64) (*blockBaseQuerier, er
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *blockBaseQuerier) LabelValues(ctx context.Context, name string, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *blockBaseQuerier) LabelValues(ctx context.Context, name string, hints *storage.LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
res, err := q.index.SortedLabelValues(ctx, name, matchers...)
|
res, err := q.index.SortedLabelValues(ctx, name, matchers...)
|
||||||
return res, nil, err
|
return res, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *blockBaseQuerier) LabelNames(ctx context.Context, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (q *blockBaseQuerier) LabelNames(ctx context.Context, hints *storage.LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
res, err := q.index.LabelNames(ctx, matchers...)
|
res, err := q.index.LabelNames(ctx, matchers...)
|
||||||
return res, nil, err
|
return res, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3022,7 +3022,7 @@ func TestQuerierIndexQueriesRace(t *testing.T) {
|
||||||
q, err := db.Querier(math.MinInt64, math.MaxInt64)
|
q, err := db.Querier(math.MinInt64, math.MaxInt64)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
values, _, err := q.LabelValues(ctx, "seq", c.matchers...)
|
values, _, err := q.LabelValues(ctx, "seq", nil, c.matchers...)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Emptyf(t, values, `label values for label "seq" should be empty`)
|
require.Emptyf(t, values, `label values for label "seq" should be empty`)
|
||||||
|
|
||||||
|
|
|
@ -658,6 +658,10 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hints := &storage.LabelHints{
|
||||||
|
Limit: toHintLimit(limit),
|
||||||
|
}
|
||||||
|
|
||||||
q, err := api.Queryable.Querier(timestamp.FromTime(start), timestamp.FromTime(end))
|
q, err := api.Queryable.Querier(timestamp.FromTime(start), timestamp.FromTime(end))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
return apiFuncResult{nil, returnAPIError(err), nil, nil}
|
||||||
|
@ -672,7 +676,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
labelNamesSet := make(map[string]struct{})
|
labelNamesSet := make(map[string]struct{})
|
||||||
|
|
||||||
for _, matchers := range matcherSets {
|
for _, matchers := range matcherSets {
|
||||||
vals, callWarnings, err := q.LabelNames(r.Context(), matchers...)
|
vals, callWarnings, err := q.LabelNames(r.Context(), hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, returnAPIError(err), warnings, nil}
|
return apiFuncResult{nil, returnAPIError(err), warnings, nil}
|
||||||
}
|
}
|
||||||
|
@ -694,7 +698,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
if len(matcherSets) == 1 {
|
if len(matcherSets) == 1 {
|
||||||
matchers = matcherSets[0]
|
matchers = matcherSets[0]
|
||||||
}
|
}
|
||||||
names, warnings, err = q.LabelNames(r.Context(), matchers...)
|
names, warnings, err = q.LabelNames(r.Context(), hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, nil}
|
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, nil}
|
||||||
}
|
}
|
||||||
|
@ -704,7 +708,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
names = []string{}
|
names = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(names) > limit {
|
if limit > 0 && len(names) > limit {
|
||||||
names = names[:limit]
|
names = names[:limit]
|
||||||
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
||||||
}
|
}
|
||||||
|
@ -738,6 +742,10 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hints := &storage.LabelHints{
|
||||||
|
Limit: toHintLimit(limit),
|
||||||
|
}
|
||||||
|
|
||||||
q, err := api.Queryable.Querier(timestamp.FromTime(start), timestamp.FromTime(end))
|
q, err := api.Queryable.Querier(timestamp.FromTime(start), timestamp.FromTime(end))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
|
||||||
|
@ -762,7 +770,7 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
var callWarnings annotations.Annotations
|
var callWarnings annotations.Annotations
|
||||||
labelValuesSet := make(map[string]struct{})
|
labelValuesSet := make(map[string]struct{})
|
||||||
for _, matchers := range matcherSets {
|
for _, matchers := range matcherSets {
|
||||||
vals, callWarnings, err = q.LabelValues(ctx, name, matchers...)
|
vals, callWarnings, err = q.LabelValues(ctx, name, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, closer}
|
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, closer}
|
||||||
}
|
}
|
||||||
|
@ -781,7 +789,7 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
if len(matcherSets) == 1 {
|
if len(matcherSets) == 1 {
|
||||||
matchers = matcherSets[0]
|
matchers = matcherSets[0]
|
||||||
}
|
}
|
||||||
vals, warnings, err = q.LabelValues(ctx, name, matchers...)
|
vals, warnings, err = q.LabelValues(ctx, name, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, closer}
|
return apiFuncResult{nil, &apiError{errorExec, err}, warnings, closer}
|
||||||
}
|
}
|
||||||
|
@ -793,7 +801,7 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
|
|
||||||
slices.Sort(vals)
|
slices.Sort(vals)
|
||||||
|
|
||||||
if len(vals) > limit {
|
if limit > 0 && len(vals) > limit {
|
||||||
vals = vals[:limit]
|
vals = vals[:limit]
|
||||||
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
||||||
}
|
}
|
||||||
|
@ -863,6 +871,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
||||||
Start: timestamp.FromTime(start),
|
Start: timestamp.FromTime(start),
|
||||||
End: timestamp.FromTime(end),
|
End: timestamp.FromTime(end),
|
||||||
Func: "series", // There is no series function, this token is used for lookups that don't need samples.
|
Func: "series", // There is no series function, this token is used for lookups that don't need samples.
|
||||||
|
Limit: toHintLimit(limit),
|
||||||
}
|
}
|
||||||
var set storage.SeriesSet
|
var set storage.SeriesSet
|
||||||
|
|
||||||
|
@ -889,7 +898,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
||||||
}
|
}
|
||||||
metrics = append(metrics, set.At().Labels())
|
metrics = append(metrics, set.At().Labels())
|
||||||
|
|
||||||
if len(metrics) > limit {
|
if limit > 0 && len(metrics) > limit {
|
||||||
metrics = metrics[:limit]
|
metrics = metrics[:limit]
|
||||||
warnings.Add(errors.New("results truncated due to limit"))
|
warnings.Add(errors.New("results truncated due to limit"))
|
||||||
return apiFuncResult{metrics, nil, warnings, closer}
|
return apiFuncResult{metrics, nil, warnings, closer}
|
||||||
|
@ -1898,8 +1907,8 @@ OUTER:
|
||||||
return matcherSets, nil
|
return matcherSets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseLimitParam returning 0 means no limit is to be applied.
|
||||||
func parseLimitParam(limitStr string) (limit int, err error) {
|
func parseLimitParam(limitStr string) (limit int, err error) {
|
||||||
limit = math.MaxInt
|
|
||||||
if limitStr == "" {
|
if limitStr == "" {
|
||||||
return limit, nil
|
return limit, nil
|
||||||
}
|
}
|
||||||
|
@ -1908,9 +1917,19 @@ func parseLimitParam(limitStr string) (limit int, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return limit, err
|
return limit, err
|
||||||
}
|
}
|
||||||
if limit <= 0 {
|
if limit < 0 {
|
||||||
return limit, errors.New("limit must be positive")
|
return limit, errors.New("limit must be non-negative")
|
||||||
}
|
}
|
||||||
|
|
||||||
return limit, nil
|
return limit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toHintLimit increases the API limit, as returned by parseLimitParam, by 1.
|
||||||
|
// This allows for emitting warnings when the results are truncated.
|
||||||
|
func toHintLimit(limit int) int {
|
||||||
|
// 0 means no limit and avoid int overflow
|
||||||
|
if limit > 0 && limit < math.MaxInt {
|
||||||
|
return limit + 1
|
||||||
|
}
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
|
|
@ -739,13 +739,16 @@ func TestLabelNames(t *testing.T) {
|
||||||
api := &API{
|
api := &API{
|
||||||
Queryable: storage,
|
Queryable: storage,
|
||||||
}
|
}
|
||||||
request := func(method string, matchers ...string) (*http.Request, error) {
|
request := func(method, limit string, matchers ...string) (*http.Request, error) {
|
||||||
u, err := url.Parse("http://example.com")
|
u, err := url.Parse("http://example.com")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
q := u.Query()
|
q := u.Query()
|
||||||
for _, matcher := range matchers {
|
for _, matcher := range matchers {
|
||||||
q.Add("match[]", matcher)
|
q.Add("match[]", matcher)
|
||||||
}
|
}
|
||||||
|
if limit != "" {
|
||||||
|
q.Add("limit", limit)
|
||||||
|
}
|
||||||
u.RawQuery = q.Encode()
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
r, err := http.NewRequest(method, u.String(), nil)
|
r, err := http.NewRequest(method, u.String(), nil)
|
||||||
|
@ -759,6 +762,7 @@ func TestLabelNames(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
api *API
|
api *API
|
||||||
matchers []string
|
matchers []string
|
||||||
|
limit string
|
||||||
expected []string
|
expected []string
|
||||||
expectedErrorType errorType
|
expectedErrorType errorType
|
||||||
}{
|
}{
|
||||||
|
@ -773,6 +777,13 @@ func TestLabelNames(t *testing.T) {
|
||||||
expected: []string{"__name__", "abc", "foo", "xyz"},
|
expected: []string{"__name__", "abc", "foo", "xyz"},
|
||||||
api: api,
|
api: api,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "non empty label matcher with limit",
|
||||||
|
matchers: []string{`{foo=~".+"}`},
|
||||||
|
expected: []string{"__name__", "abc"},
|
||||||
|
limit: "2",
|
||||||
|
api: api,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "exact label matcher",
|
name: "exact label matcher",
|
||||||
matchers: []string{`{foo="boo"}`},
|
matchers: []string{`{foo="boo"}`},
|
||||||
|
@ -805,7 +816,7 @@ func TestLabelNames(t *testing.T) {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
for _, method := range []string{http.MethodGet, http.MethodPost} {
|
for _, method := range []string{http.MethodGet, http.MethodPost} {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
req, err := request(method, tc.matchers...)
|
req, err := request(method, tc.limit, tc.matchers...)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
res := tc.api.labelNames(req.WithContext(ctx))
|
res := tc.api.labelNames(req.WithContext(ctx))
|
||||||
assertAPIError(t, res.err, tc.expectedErrorType)
|
assertAPIError(t, res.err, tc.expectedErrorType)
|
||||||
|
@ -1430,6 +1441,15 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
||||||
responseLen: 2, // API does not specify which particular value will come back.
|
responseLen: 2, // API does not specify which particular value will come back.
|
||||||
warningsCount: 0, // No warnings if limit isn't exceeded.
|
warningsCount: 0, // No warnings if limit isn't exceeded.
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
endpoint: api.series,
|
||||||
|
query: url.Values{
|
||||||
|
"match[]": []string{"test_metric1"},
|
||||||
|
"limit": []string{"0"},
|
||||||
|
},
|
||||||
|
responseLen: 2, // API does not specify which particular value will come back.
|
||||||
|
warningsCount: 0, // No warnings if limit isn't exceeded.
|
||||||
|
},
|
||||||
// Missing match[] query params in series requests.
|
// Missing match[] query params in series requests.
|
||||||
{
|
{
|
||||||
endpoint: api.series,
|
endpoint: api.series,
|
||||||
|
|
|
@ -170,11 +170,11 @@ type errorTestQuerier struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t errorTestQuerier) LabelValues(context.Context, string, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (t errorTestQuerier) LabelValues(context.Context, string, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, t.err
|
return nil, nil, t.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t errorTestQuerier) LabelNames(context.Context, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (t errorTestQuerier) LabelNames(context.Context, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
return nil, nil, t.err
|
return nil, nil, t.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue