github.com/thanos-io/thanos@v0.32.5/pkg/exemplars/tsdb.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package exemplars 5 6 import ( 7 "sync" 8 9 "github.com/gogo/status" 10 "github.com/pkg/errors" 11 "github.com/prometheus/prometheus/model/labels" 12 "github.com/prometheus/prometheus/storage" 13 "google.golang.org/grpc/codes" 14 15 "github.com/thanos-io/thanos/pkg/exemplars/exemplarspb" 16 "github.com/thanos-io/thanos/pkg/store/labelpb" 17 ) 18 19 // TSDB allows fetching exemplars from a TSDB instance. 20 type TSDB struct { 21 db storage.ExemplarQueryable 22 23 extLabels labels.Labels 24 mtx sync.RWMutex 25 } 26 27 // NewTSDB creates new exemplars.TSDB. 28 func NewTSDB(db storage.ExemplarQueryable, extLabels labels.Labels) *TSDB { 29 return &TSDB{ 30 db: db, 31 extLabels: extLabels, 32 } 33 } 34 35 func (t *TSDB) SetExtLabels(extLabels labels.Labels) { 36 t.mtx.Lock() 37 defer t.mtx.Unlock() 38 39 t.extLabels = extLabels 40 } 41 42 func (t *TSDB) getExtLabels() labels.Labels { 43 t.mtx.RLock() 44 defer t.mtx.RUnlock() 45 46 return t.extLabels 47 } 48 49 // Exemplars returns all specified exemplars from a TSDB instance. 50 func (t *TSDB) Exemplars(matchers [][]*labels.Matcher, start, end int64, s exemplarspb.Exemplars_ExemplarsServer) error { 51 match, selectors := selectorsMatchesExternalLabels(matchers, t.getExtLabels()) 52 53 if !match { 54 return nil 55 } 56 57 if len(selectors) == 0 { 58 return status.Error(codes.InvalidArgument, errors.New("no matchers specified (excluding external labels)").Error()) 59 } 60 61 eq, err := t.db.ExemplarQuerier(s.Context()) 62 if err != nil { 63 return status.Error(codes.Internal, err.Error()) 64 } 65 66 exemplars, err := eq.Select(start, end, selectors...) 67 if err != nil { 68 return status.Error(codes.Internal, err.Error()) 69 } 70 71 for _, e := range exemplars { 72 exd := exemplarspb.ExemplarData{ 73 SeriesLabels: labelpb.ZLabelSet{ 74 Labels: labelpb.ZLabelsFromPromLabels(labelpb.ExtendSortedLabels(e.SeriesLabels, t.getExtLabels())), 75 }, 76 Exemplars: exemplarspb.ExemplarsFromPromExemplars(e.Exemplars), 77 } 78 if err := s.Send(exemplarspb.NewExemplarsResponse(&exd)); err != nil { 79 return status.Error(codes.Aborted, err.Error()) 80 } 81 } 82 return nil 83 } 84 85 // selectorsMatchesExternalLabels returns false if none of the selectors matches the external labels. 86 // If true, it also returns an array of non-empty Prometheus matchers. 87 func selectorsMatchesExternalLabels(selectors [][]*labels.Matcher, externalLabels labels.Labels) (bool, [][]*labels.Matcher) { 88 matchedOnce := false 89 90 var newSelectors [][]*labels.Matcher 91 for _, m := range selectors { 92 match, m := matchesExternalLabels(m, externalLabels) 93 94 matchedOnce = matchedOnce || match 95 if match && len(m) > 0 { 96 newSelectors = append(newSelectors, m) 97 } 98 } 99 100 return matchedOnce, newSelectors 101 }