1
2
3
4
5
6
7
8
9
10
11
12
13
14 package types
15
16 import (
17 "strings"
18 "sync"
19 "time"
20
21 "github.com/prometheus/client_golang/prometheus"
22 "github.com/prometheus/common/model"
23
24 "github.com/prometheus/alertmanager/pkg/labels"
25 )
26
27
28 type AlertState string
29
30
31 const (
32 AlertStateUnprocessed AlertState = "unprocessed"
33 AlertStateActive AlertState = "active"
34 AlertStateSuppressed AlertState = "suppressed"
35 )
36
37
38
39
40
41
42
43 type AlertStatus struct {
44 State AlertState `json:"state"`
45 SilencedBy []string `json:"silencedBy"`
46 InhibitedBy []string `json:"inhibitedBy"`
47
48
49 pendingSilences []string
50 silencesVersion int
51 }
52
53
54
55 type Marker interface {
56
57
58
59
60
61
62 SetActiveOrSilenced(alert model.Fingerprint, version int, activeSilenceIDs, pendingSilenceIDs []string)
63
64
65
66
67
68
69
70
71 SetInhibited(alert model.Fingerprint, alertIDs ...string)
72
73
74
75 Count(...AlertState) int
76
77
78 Status(model.Fingerprint) AlertStatus
79
80 Delete(model.Fingerprint)
81
82
83
84
85
86
87 Unprocessed(model.Fingerprint) bool
88 Active(model.Fingerprint) bool
89 Silenced(model.Fingerprint) (activeIDs, pendingIDs []string, version int, silenced bool)
90 Inhibited(model.Fingerprint) ([]string, bool)
91 }
92
93
94 func NewMarker(r prometheus.Registerer) Marker {
95 m := &memMarker{
96 m: map[model.Fingerprint]*AlertStatus{},
97 }
98
99 m.registerMetrics(r)
100
101 return m
102 }
103
104 type memMarker struct {
105 m map[model.Fingerprint]*AlertStatus
106
107 mtx sync.RWMutex
108 }
109
110 func (m *memMarker) registerMetrics(r prometheus.Registerer) {
111 newMarkedAlertMetricByState := func(st AlertState) prometheus.GaugeFunc {
112 return prometheus.NewGaugeFunc(
113 prometheus.GaugeOpts{
114 Name: "alertmanager_marked_alerts",
115 Help: "How many alerts by state are currently marked in the Alertmanager regardless of their expiry.",
116 ConstLabels: prometheus.Labels{"state": string(st)},
117 },
118 func() float64 {
119 return float64(m.Count(st))
120 },
121 )
122 }
123
124 alertsActive := newMarkedAlertMetricByState(AlertStateActive)
125 alertsSuppressed := newMarkedAlertMetricByState(AlertStateSuppressed)
126 alertStateUnprocessed := newMarkedAlertMetricByState(AlertStateUnprocessed)
127
128 r.MustRegister(alertsActive)
129 r.MustRegister(alertsSuppressed)
130 r.MustRegister(alertStateUnprocessed)
131 }
132
133
134 func (m *memMarker) Count(states ...AlertState) int {
135 m.mtx.RLock()
136 defer m.mtx.RUnlock()
137
138 if len(states) == 0 {
139 return len(m.m)
140 }
141
142 var count int
143 for _, status := range m.m {
144 for _, state := range states {
145 if status.State == state {
146 count++
147 }
148 }
149 }
150 return count
151 }
152
153
154 func (m *memMarker) SetActiveOrSilenced(alert model.Fingerprint, version int, activeIDs, pendingIDs []string) {
155 m.mtx.Lock()
156 defer m.mtx.Unlock()
157
158 s, found := m.m[alert]
159 if !found {
160 s = &AlertStatus{}
161 m.m[alert] = s
162 }
163 s.SilencedBy = activeIDs
164 s.pendingSilences = pendingIDs
165 s.silencesVersion = version
166
167
168
169
170 if len(activeIDs) == 0 && len(s.InhibitedBy) == 0 {
171 s.State = AlertStateActive
172 return
173 }
174
175 s.State = AlertStateSuppressed
176 }
177
178
179 func (m *memMarker) SetInhibited(alert model.Fingerprint, ids ...string) {
180 m.mtx.Lock()
181 defer m.mtx.Unlock()
182
183 s, found := m.m[alert]
184 if !found {
185 s = &AlertStatus{}
186 m.m[alert] = s
187 }
188 s.InhibitedBy = ids
189
190
191
192
193 if len(ids) == 0 && len(s.SilencedBy) == 0 {
194 s.State = AlertStateActive
195 return
196 }
197
198 s.State = AlertStateSuppressed
199 }
200
201
202 func (m *memMarker) Status(alert model.Fingerprint) AlertStatus {
203 m.mtx.RLock()
204 defer m.mtx.RUnlock()
205
206 if s, found := m.m[alert]; found {
207 return *s
208 }
209 return AlertStatus{
210 State: AlertStateUnprocessed,
211 SilencedBy: []string{},
212 InhibitedBy: []string{},
213 }
214 }
215
216
217 func (m *memMarker) Delete(alert model.Fingerprint) {
218 m.mtx.Lock()
219 defer m.mtx.Unlock()
220
221 delete(m.m, alert)
222 }
223
224
225 func (m *memMarker) Unprocessed(alert model.Fingerprint) bool {
226 return m.Status(alert).State == AlertStateUnprocessed
227 }
228
229
230 func (m *memMarker) Active(alert model.Fingerprint) bool {
231 return m.Status(alert).State == AlertStateActive
232 }
233
234
235 func (m *memMarker) Inhibited(alert model.Fingerprint) ([]string, bool) {
236 s := m.Status(alert)
237 return s.InhibitedBy,
238 s.State == AlertStateSuppressed && len(s.InhibitedBy) > 0
239 }
240
241
242
243
244 func (m *memMarker) Silenced(alert model.Fingerprint) (activeIDs, pendingIDs []string, version int, silenced bool) {
245 s := m.Status(alert)
246 return s.SilencedBy, s.pendingSilences, s.silencesVersion,
247 s.State == AlertStateSuppressed && len(s.SilencedBy) > 0
248 }
249
250
251
252 type MultiError struct {
253 mtx sync.Mutex
254 errors []error
255 }
256
257
258 func (e *MultiError) Add(err error) {
259 e.mtx.Lock()
260 defer e.mtx.Unlock()
261
262 e.errors = append(e.errors, err)
263 }
264
265
266 func (e *MultiError) Len() int {
267 e.mtx.Lock()
268 defer e.mtx.Unlock()
269
270 return len(e.errors)
271 }
272
273
274
275 func (e *MultiError) Errors() []error {
276 e.mtx.Lock()
277 defer e.mtx.Unlock()
278
279 return append(make([]error, 0, len(e.errors)), e.errors...)
280 }
281
282 func (e *MultiError) Error() string {
283 e.mtx.Lock()
284 defer e.mtx.Unlock()
285
286 es := make([]string, 0, len(e.errors))
287 for _, err := range e.errors {
288 es = append(es, err.Error())
289 }
290 return strings.Join(es, "; ")
291 }
292
293
294
295
296
297 type Alert struct {
298 model.Alert
299
300
301 UpdatedAt time.Time
302 Timeout bool
303 }
304
305
306 type AlertSlice []*Alert
307
308 func (as AlertSlice) Less(i, j int) bool {
309
310 for _, overrideKey := range [...]model.LabelName{"job", "instance"} {
311 iVal, iOk := as[i].Labels[overrideKey]
312 jVal, jOk := as[j].Labels[overrideKey]
313 if !iOk && !jOk {
314 continue
315 }
316 if !iOk {
317 return false
318 }
319 if !jOk {
320 return true
321 }
322 if iVal != jVal {
323 return iVal < jVal
324 }
325 }
326 return as[i].Labels.Before(as[j].Labels)
327 }
328 func (as AlertSlice) Swap(i, j int) { as[i], as[j] = as[j], as[i] }
329 func (as AlertSlice) Len() int { return len(as) }
330
331
332
333 func Alerts(alerts ...*Alert) model.Alerts {
334 res := make(model.Alerts, 0, len(alerts))
335 for _, a := range alerts {
336 v := a.Alert
337
338 if !a.Resolved() {
339 v.EndsAt = time.Time{}
340 }
341 res = append(res, &v)
342 }
343 return res
344 }
345
346
347
348
349 func (a *Alert) Merge(o *Alert) *Alert {
350
351 if o.UpdatedAt.Before(a.UpdatedAt) {
352 return o.Merge(a)
353 }
354
355 res := *o
356
357
358 if a.StartsAt.Before(o.StartsAt) {
359 res.StartsAt = a.StartsAt
360 }
361
362 if o.Resolved() {
363
364 if a.Resolved() && a.EndsAt.After(o.EndsAt) {
365 res.EndsAt = a.EndsAt
366 }
367 } else {
368
369 if a.EndsAt.After(o.EndsAt) && !a.Timeout {
370 res.EndsAt = a.EndsAt
371 }
372 }
373
374 return &res
375 }
376
377
378
379
380 type Muter interface {
381 Mutes(model.LabelSet) bool
382 }
383
384
385 type MuteFunc func(model.LabelSet) bool
386
387
388 func (f MuteFunc) Mutes(lset model.LabelSet) bool { return f(lset) }
389
390
391 type Silence struct {
392
393 ID string `json:"id"`
394
395
396 Matchers labels.Matchers `json:"matchers"`
397
398
399
400
401
402
403
404
405
406
407 StartsAt time.Time `json:"startsAt"`
408 EndsAt time.Time `json:"endsAt"`
409
410
411 UpdatedAt time.Time `json:"updatedAt"`
412
413
414 CreatedBy string `json:"createdBy"`
415 Comment string `json:"comment,omitempty"`
416
417 Status SilenceStatus `json:"status"`
418 }
419
420
421
422 func (s *Silence) Expired() bool {
423 return s.StartsAt.Equal(s.EndsAt)
424 }
425
426
427 type SilenceStatus struct {
428 State SilenceState `json:"state"`
429 }
430
431
432 type SilenceState string
433
434
435 const (
436 SilenceStateExpired SilenceState = "expired"
437 SilenceStateActive SilenceState = "active"
438 SilenceStatePending SilenceState = "pending"
439 )
440
441
442
443 func CalcSilenceState(start, end time.Time) SilenceState {
444 current := time.Now()
445 if current.Before(start) {
446 return SilenceStatePending
447 }
448 if current.Before(end) {
449 return SilenceStateActive
450 }
451 return SilenceStateExpired
452 }
453
View as plain text