github.com/thanos-io/thanos@v0.32.5/pkg/rules/queryable.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package rules 5 6 import ( 7 "context" 8 "math/rand" 9 "net/url" 10 "strings" 11 "time" 12 13 "github.com/go-kit/log" 14 "github.com/go-kit/log/level" 15 "github.com/prometheus/client_golang/prometheus" 16 "github.com/prometheus/client_golang/prometheus/promauto" 17 "github.com/prometheus/common/model" 18 "github.com/prometheus/prometheus/model/labels" 19 "github.com/prometheus/prometheus/storage" 20 21 "github.com/thanos-io/thanos/internal/cortex/querier/series" 22 "github.com/thanos-io/thanos/pkg/httpconfig" 23 "github.com/thanos-io/thanos/pkg/promclient" 24 "github.com/thanos-io/thanos/pkg/store/storepb" 25 ) 26 27 type promClientsQueryable struct { 28 httpMethod string 29 step time.Duration 30 31 logger log.Logger 32 promClients []*promclient.Client 33 queryClients []*httpconfig.Client 34 ignoredLabelNames []string 35 36 duplicatedQuery prometheus.Counter 37 } 38 type promClientsQuerier struct { 39 ctx context.Context 40 mint, maxt int64 41 step int64 42 httpMethod string 43 44 logger log.Logger 45 promClients []*promclient.Client 46 queryClients []*httpconfig.Client 47 restoreIgnoreLabels []string 48 49 // We use a dummy counter here because the duplicated 50 // addresses are already tracked by rule evaluation part. 51 duplicatedQuery prometheus.Counter 52 } 53 54 // NewPromClientsQueryable creates a queryable that queries queriers from Prometheus clients. 55 func NewPromClientsQueryable(logger log.Logger, queryClients []*httpconfig.Client, promClients []*promclient.Client, 56 httpMethod string, step time.Duration, ignoredLabelNames []string) *promClientsQueryable { 57 return &promClientsQueryable{ 58 logger: logger, 59 queryClients: queryClients, 60 promClients: promClients, 61 duplicatedQuery: promauto.With(nil).NewCounter(prometheus.CounterOpts{}), 62 httpMethod: httpMethod, 63 step: step, 64 ignoredLabelNames: ignoredLabelNames, 65 } 66 } 67 68 // Querier returns a new Querier for the given time range. 69 func (q *promClientsQueryable) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) { 70 return &promClientsQuerier{ 71 ctx: ctx, 72 mint: mint, 73 maxt: maxt, 74 step: int64(q.step / time.Second), 75 httpMethod: q.httpMethod, 76 logger: q.logger, 77 queryClients: q.queryClients, 78 promClients: q.promClients, 79 restoreIgnoreLabels: q.ignoredLabelNames, 80 }, nil 81 } 82 83 // Select implements storage.Querier interface. 84 func (q *promClientsQuerier) Select(_ bool, _ *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet { 85 query := storepb.PromMatchersToString(matchers...) 86 87 for _, i := range rand.Perm(len(q.queryClients)) { 88 promClient := q.promClients[i] 89 endpoints := RemoveDuplicateQueryEndpoints(q.logger, q.duplicatedQuery, q.queryClients[i].Endpoints()) 90 for _, i := range rand.Perm(len(endpoints)) { 91 m, warns, _, err := promClient.QueryRange(q.ctx, endpoints[i], query, q.mint, q.maxt, q.step, promclient.QueryOptions{ 92 Deduplicate: true, 93 Method: q.httpMethod, 94 }) 95 96 if err != nil { 97 level.Error(q.logger).Log("err", err, "query", q) 98 continue 99 } 100 if len(warns) > 0 { 101 level.Warn(q.logger).Log("warnings", strings.Join(warns, ", "), "query", q) 102 } 103 matrix := make([]*model.SampleStream, 0, m.Len()) 104 for _, metric := range m { 105 for _, label := range q.restoreIgnoreLabels { 106 delete(metric.Metric, model.LabelName(label)) 107 } 108 109 matrix = append(matrix, &model.SampleStream{ 110 Metric: metric.Metric, 111 Values: metric.Values, 112 }) 113 } 114 115 return series.MatrixToSeriesSet(matrix) 116 } 117 } 118 return storage.NoopSeriesSet() 119 } 120 121 // LabelValues implements storage.LabelQuerier interface. 122 func (q *promClientsQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { 123 return nil, nil, nil 124 } 125 126 // LabelNames implements storage.LabelQuerier interface. 127 func (q *promClientsQuerier) LabelNames(matchers ...*labels.Matcher) ([]string, storage.Warnings, error) { 128 return nil, nil, nil 129 } 130 131 // Close implements storage.LabelQuerier interface. 132 func (q *promClientsQuerier) Close() error { 133 return nil 134 } 135 136 // RemoveDuplicateQueryEndpoints removes duplicate endpoints from the list of urls. 137 func RemoveDuplicateQueryEndpoints(logger log.Logger, duplicatedQueriers prometheus.Counter, urls []*url.URL) []*url.URL { 138 set := make(map[string]struct{}) 139 deduplicated := make([]*url.URL, 0, len(urls)) 140 for _, u := range urls { 141 if _, ok := set[u.String()]; ok { 142 level.Warn(logger).Log("msg", "duplicate query address is provided", "addr", u.String()) 143 duplicatedQueriers.Inc() 144 continue 145 } 146 deduplicated = append(deduplicated, u) 147 set[u.String()] = struct{}{} 148 } 149 return deduplicated 150 }