cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.35.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/promapi/failover.go

196lines · 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}
56
57func NewFailoverGroup(name string, servers []*Prometheus, strictErrors bool, uptimeMetric string, include, exclude []*regexp.Regexp) *FailoverGroup {
58 return &FailoverGroup{
59 name: name,
60 servers: servers,
61 strictErrors: strictErrors,
62 uptimeMetric: uptimeMetric,
63 pathsInclude: include,
64 pathsExclude: exclude,
65 }
66}
67
68func (fg *FailoverGroup) Name() string {
69 return fg.name
70}
71
72func (fg *FailoverGroup) UptimeMetric() string {
73 return fg.uptimeMetric
74}
75
76func (fg *FailoverGroup) IsEnabledForPath(path string) bool {
77 if len(fg.pathsInclude) == 0 && len(fg.pathsExclude) == 0 {
78 return true
79 }
80 for _, re := range fg.pathsExclude {
81 if re.MatchString(path) {
82 return false
83 }
84 }
85 for _, re := range fg.pathsInclude {
86 if re.MatchString(path) {
87 return true
88 }
89 }
90 return false
91}
92
93func (fg *FailoverGroup) StartWorkers() {
94 queryCache := newQueryCache(time.Hour)
95 fg.quitChan = make(chan bool)
96 go cacheCleaner(queryCache, time.Minute*2, fg.quitChan)
97
98 fg.cacheCollector = newCacheCollector(queryCache, fg.name)
99 prometheus.MustRegister(fg.cacheCollector)
100 for _, prom := range fg.servers {
101 prom.cache = queryCache
102 prom.StartWorkers()
103 }
104}
105
106func (fg *FailoverGroup) Close() {
107 for _, prom := range fg.servers {
108 prom.Close()
109 }
110 prometheus.Unregister(fg.cacheCollector)
111 fg.quitChan <- true
112}
113
114func (fg *FailoverGroup) CleanCache() {
115 for _, prom := range fg.servers {
116 if prom.cache != nil {
117 prom.cache.gc()
118 return
119 }
120 }
121}
122
123func (fg *FailoverGroup) Config(ctx context.Context) (cfg *ConfigResult, err error) {
124 var uri string
125 for _, prom := range fg.servers {
126 uri = prom.safeURI
127 cfg, err = prom.Config(ctx)
128 if err == nil {
129 return
130 }
131 if !IsUnavailableError(err) {
132 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
133 }
134 }
135 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
136}
137
138func (fg *FailoverGroup) Query(ctx context.Context, expr string) (qr *QueryResult, err error) {
139 var uri string
140 for _, prom := range fg.servers {
141 uri = prom.safeURI
142 qr, err = prom.Query(ctx, expr)
143 if err == nil {
144 return
145 }
146 if !IsUnavailableError(err) {
147 return qr, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
148 }
149 }
150 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
151}
152
153func (fg *FailoverGroup) RangeQuery(ctx context.Context, expr string, params RangeQueryTimes) (rqr *RangeQueryResult, err error) {
154 var uri string
155 for _, prom := range fg.servers {
156 uri = prom.safeURI
157 rqr, err = prom.RangeQuery(ctx, expr, params)
158 if err == nil {
159 return
160 }
161 if !IsUnavailableError(err) {
162 return rqr, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
163 }
164 }
165 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
166}
167
168func (fg *FailoverGroup) Metadata(ctx context.Context, metric string) (metadata *MetadataResult, err error) {
169 var uri string
170 for _, prom := range fg.servers {
171 uri = prom.safeURI
172 metadata, err = prom.Metadata(ctx, metric)
173 if err == nil {
174 return
175 }
176 if !IsUnavailableError(err) {
177 return metadata, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
178 }
179 }
180 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
181}
182
183func (fg *FailoverGroup) Flags(ctx context.Context) (flags *FlagsResult, err error) {
184 var uri string
185 for _, prom := range fg.servers {
186 uri = prom.safeURI
187 flags, err = prom.Flags(ctx)
188 if err == nil {
189 return
190 }
191 if !IsUnavailableError(err) {
192 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
193 }
194 }
195 return nil, &FailoverGroupError{err: err, uri: uri, isStrict: fg.strictErrors}
196}
197