cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.42.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/failover.go

202lines · modecode

1package promapi
2
3import (
4 "context"
5 "regexp"
6 "time"
7
8 "github.com/prometheus/client_golang/prometheus"
9)
10
11type FailoverGroupError struct {
12 err error
13 uri string
14 isStrict bool
15}
16
17func (e *FailoverGroupError) Unwrap() error {
18 return e.err
19}
20
21func (e *FailoverGroupError) Error() string {
22 return e.err.Error()
23}
24
25func (e *FailoverGroupError) URI() string {
26 return e.uri
27}
28
29func (e *FailoverGroupError) IsStrict() bool {
30 return e.isStrict
31}
32
33func cacheCleaner(cache *queryCache, interval time.Duration, quit chan bool) {
34 ticker := time.NewTicker(interval)
35 for {
36 select {
37 case <-quit:
38 return
39 case <-ticker.C:
40 cache.gc()
41 }
42 }
43}
44
45type FailoverGroup struct {
46 name string
47 servers []*Prometheus
48 strictErrors bool
49 uptimeMetric string
50 cacheCollector *cacheCollector
51 quitChan chan bool
52
53 pathsInclude []*regexp.Regexp
54 pathsExclude []*regexp.Regexp
55 tags []string
56}
57
58func NewFailoverGroup(name string, servers []*Prometheus, strictErrors bool, uptimeMetric string, include, exclude []*regexp.Regexp, tags []string) *FailoverGroup {
59 return &FailoverGroup{
60 name: name,
61 servers: servers,
62 strictErrors: strictErrors,
63 uptimeMetric: uptimeMetric,
64 pathsInclude: include,
65 pathsExclude: exclude,
66 tags: tags,
67 }
68}
69
70func (fg *FailoverGroup) Name() string {
71 return fg.name
72}
73
74func (fg *FailoverGroup) Tags() []string {
75 return fg.tags
76}
77
78func (fg *FailoverGroup) UptimeMetric() string {
79 return fg.uptimeMetric
80}
81
82func (fg *FailoverGroup) IsEnabledForPath(path string) bool {
83 if len(fg.pathsInclude) == 0 && len(fg.pathsExclude) == 0 {
84 return true
85 }
86 for _, re := range fg.pathsExclude {
87 if re.MatchString(path) {
88 return false
89 }
90 }
91 for _, re := range fg.pathsInclude {
92 if re.MatchString(path) {
93 return true
94 }
95 }
96 return false
97}
98
99func (fg *FailoverGroup) StartWorkers() {
100 queryCache := newQueryCache(time.Hour)
101 fg.quitChan = make(chan bool)
102 go cacheCleaner(queryCache, time.Minute*2, fg.quitChan)
103
104 fg.cacheCollector = newCacheCollector(queryCache, fg.name)
105 prometheus.MustRegister(fg.cacheCollector)
106 for _, prom := range fg.servers {
107 prom.cache = queryCache
108 prom.StartWorkers()
109 }
110}
111
112func (fg *FailoverGroup) Close() {
113 for _, prom := range fg.servers {
114 prom.Close()
115 }
116 prometheus.Unregister(fg.cacheCollector)
117 fg.quitChan <- true
118}
119
120func (fg *FailoverGroup) CleanCache() {
121 for _, prom := range fg.servers {
122 if prom.cache != nil {
123 prom.cache.gc()
124 return
125 }
126 }
127}
128
129func (fg *FailoverGroup) Config(ctx context.Context) (cfg *ConfigResult, err error) {
130 var uri string
131 for _, prom := range fg.servers {
132 uri = prom.safeURI
133 cfg, err = prom.Config(ctx)
134 if err == nil {
135 return
136 }
137 if !IsUnavailableError(err) {
138 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
139 }
140 }
141 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
142}
143
144func (fg *FailoverGroup) Query(ctx context.Context, expr string) (qr *QueryResult, err error) {
145 var uri string
146 for _, prom := range fg.servers {
147 uri = prom.safeURI
148 qr, err = prom.Query(ctx, expr)
149 if err == nil {
150 return
151 }
152 if !IsUnavailableError(err) {
153 return qr, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
154 }
155 }
156 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
157}
158
159func (fg *FailoverGroup) RangeQuery(ctx context.Context, expr string, params RangeQueryTimes) (rqr *RangeQueryResult, err error) {
160 var uri string
161 for _, prom := range fg.servers {
162 uri = prom.safeURI
163 rqr, err = prom.RangeQuery(ctx, expr, params)
164 if err == nil {
165 return
166 }
167 if !IsUnavailableError(err) {
168 return rqr, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
169 }
170 }
171 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
172}
173
174func (fg *FailoverGroup) Metadata(ctx context.Context, metric string) (metadata *MetadataResult, err error) {
175 var uri string
176 for _, prom := range fg.servers {
177 uri = prom.safeURI
178 metadata, err = prom.Metadata(ctx, metric)
179 if err == nil {
180 return
181 }
182 if !IsUnavailableError(err) {
183 return metadata, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
184 }
185 }
186 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
187}
188
189func (fg *FailoverGroup) Flags(ctx context.Context) (flags *FlagsResult, err error) {
190 var uri string
191 for _, prom := range fg.servers {
192 uri = prom.safeURI
193 flags, err = prom.Flags(ctx)
194 if err == nil {
195 return
196 }
197 if !IsUnavailableError(err) {
198 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
199 }
200 }
201 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
202}
203