alertmanager/types/types.go

304 lines
7.7 KiB
Go
Raw Permalink Normal View History

2015-10-11 15:24:49 +00:00
// Copyright 2015 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-09-25 12:38:22 +00:00
package types
2015-09-25 16:14:46 +00:00
import (
"fmt"
"sort"
2015-10-11 10:40:43 +00:00
"strings"
"sync"
2015-09-25 16:14:46 +00:00
"time"
"github.com/prometheus/common/model"
)
// Marker helps to mark alerts as silenced and/or inhibited.
// All methods are goroutine-safe.
type Marker interface {
SetInhibited(alert model.Fingerprint, b bool)
2016-08-30 09:58:27 +00:00
SetSilenced(alert model.Fingerprint, sil ...string)
2016-08-30 09:58:27 +00:00
Silenced(alert model.Fingerprint) (string, bool)
Inhibited(alert model.Fingerprint) bool
}
// NewMarker returns an instance of a Marker implementation.
func NewMarker() Marker {
return &memMarker{
inhibited: map[model.Fingerprint]struct{}{},
2016-08-30 09:58:27 +00:00
silenced: map[model.Fingerprint]string{},
}
}
type memMarker struct {
inhibited map[model.Fingerprint]struct{}
2016-08-30 09:58:27 +00:00
silenced map[model.Fingerprint]string
mtx sync.RWMutex
}
func (m *memMarker) Inhibited(alert model.Fingerprint) bool {
m.mtx.RLock()
defer m.mtx.RUnlock()
_, ok := m.inhibited[alert]
return ok
}
2016-08-30 09:58:27 +00:00
func (m *memMarker) Silenced(alert model.Fingerprint) (string, bool) {
m.mtx.RLock()
defer m.mtx.RUnlock()
sid, ok := m.silenced[alert]
return sid, ok
}
func (m *memMarker) SetInhibited(alert model.Fingerprint, b bool) {
m.mtx.Lock()
defer m.mtx.Unlock()
if !b {
delete(m.inhibited, alert)
} else {
m.inhibited[alert] = struct{}{}
}
}
2016-08-30 09:58:27 +00:00
func (m *memMarker) SetSilenced(alert model.Fingerprint, sil ...string) {
m.mtx.Lock()
defer m.mtx.Unlock()
if len(sil) == 0 {
delete(m.silenced, alert)
} else {
m.silenced[alert] = sil[0]
}
}
// MultiError contains multiple errors and implements the error interface. Its
// zero value is ready to use. All its methods are goroutine safe.
type MultiError struct {
mtx sync.Mutex
errors []error
}
// Add adds an error to the MultiError.
func (e *MultiError) Add(err error) {
e.mtx.Lock()
defer e.mtx.Unlock()
e.errors = append(e.errors, err)
}
// Len returns the number of errors added to the MultiError.
func (e *MultiError) Len() int {
e.mtx.Lock()
defer e.mtx.Unlock()
return len(e.errors)
}
// Errors returns the errors added to the MuliError. The returned slice is a
// copy of the internal slice of errors.
func (e *MultiError) Errors() []error {
e.mtx.Lock()
defer e.mtx.Unlock()
return append(make([]error, 0, len(e.errors)), e.errors...)
}
func (e *MultiError) Error() string {
e.mtx.Lock()
defer e.mtx.Unlock()
2015-10-11 10:40:43 +00:00
es := make([]string, 0, len(e.errors))
for _, err := range e.errors {
2015-10-11 10:40:43 +00:00
es = append(es, err.Error())
}
return strings.Join(es, "; ")
}
2015-10-01 12:53:49 +00:00
// Alert wraps a model.Alert with additional information relevant
// to internal of the Alertmanager.
// The type is never exposed to external communication and the
// embedded alert has to be sanitized beforehand.
2015-09-25 12:38:22 +00:00
type Alert struct {
2015-10-01 12:53:49 +00:00
model.Alert
2015-09-25 12:38:22 +00:00
// The authoritative timestamp.
UpdatedAt time.Time
Timeout bool
WasSilenced bool `json:"-"`
WasInhibited bool `json:"-"`
}
// AlertSlice is a sortable slice of Alerts.
2015-10-27 17:24:09 +00:00
type AlertSlice []*Alert
func (as AlertSlice) Less(i, j int) bool { return as[i].UpdatedAt.Before(as[j].UpdatedAt) }
func (as AlertSlice) Swap(i, j int) { as[i], as[j] = as[j], as[i] }
func (as AlertSlice) Len() int { return len(as) }
// Alerts turns a sequence of internal alerts into a list of
// exposable model.Alert structures.
func Alerts(alerts ...*Alert) model.Alerts {
res := make(model.Alerts, 0, len(alerts))
for _, a := range alerts {
v := a.Alert
// If the end timestamp was set as the expected value in case
// of a timeout but is not reached yet, do not expose it.
if a.Timeout && !a.Resolved() {
v.EndsAt = time.Time{}
}
res = append(res, &v)
}
return res
2015-09-25 12:38:22 +00:00
}
// Merge merges the timespan of two alerts based and overwrites annotations
// based on the authoritative timestamp. A new alert is returned, the labels
// are assumed to be equal.
2015-10-02 14:52:04 +00:00
func (a *Alert) Merge(o *Alert) *Alert {
// Let o always be the younger alert.
if o.UpdatedAt.Before(a.UpdatedAt) {
2015-10-02 14:52:04 +00:00
return o.Merge(a)
}
res := *o
// Always pick the earliest starting time.
if a.StartsAt.Before(o.StartsAt) {
res.StartsAt = a.StartsAt
}
2016-02-03 13:11:59 +00:00
// A non-timeout resolved timestamp always rules.
2015-10-02 14:52:04 +00:00
// The latest explicit resolved timestamp wins.
if a.EndsAt.After(o.EndsAt) && !a.Timeout {
res.EndsAt = a.EndsAt
}
return &res
}
2015-09-25 12:38:22 +00:00
// A Muter determines whether a given label set is muted.
2015-09-28 12:13:01 +00:00
type Muter interface {
2015-09-25 16:14:46 +00:00
Mutes(model.LabelSet) bool
}
// A MuteFunc is a function that implements the Muter interface.
2015-09-28 12:13:01 +00:00
type MuteFunc func(model.LabelSet) bool
// Mutes implements the Muter interface.
2015-09-28 12:13:01 +00:00
func (f MuteFunc) Mutes(lset model.LabelSet) bool { return f(lset) }
// A Silence determines whether a given label set is muted.
2015-09-25 16:14:46 +00:00
type Silence struct {
// A unique identifier across all connected instances.
2016-08-30 09:58:27 +00:00
ID string `json:"id"`
// A set of matchers determining if a label set is affect
2015-09-27 12:07:04 +00:00
// by the silence.
Matchers Matchers `json:"matchers"`
// Time range of the silence.
//
// * StartsAt must not be before creation time
// * EndsAt must be after StartsAt
// * Deleting a silence means to set EndsAt to now
// * Time range must not be modified in different ways
//
// TODO(fabxc): this may potentially be extended by
// creation and update timestamps.
StartsAt time.Time `json:"startsAt"`
EndsAt time.Time `json:"endsAt"`
2016-05-30 17:08:57 +00:00
// The last time the silence was updated.
UpdatedAt time.Time `json:"updatedAt"`
// Information about who created the silence for which reason.
CreatedBy string `json:"createdBy"`
Comment string `json:"comment,omitempty"`
2015-09-25 16:14:46 +00:00
// timeFunc provides the time against which to evaluate
// the silence. Used for test injection.
now func() time.Time
2015-09-25 16:14:46 +00:00
}
// Validate returns true iff all fields of the silence have valid values.
func (s *Silence) Validate() error {
2016-08-30 09:58:27 +00:00
if s.ID == "" {
return fmt.Errorf("ID missing")
}
if len(s.Matchers) == 0 {
return fmt.Errorf("at least one matcher required")
2015-09-27 12:25:56 +00:00
}
2015-10-01 15:50:15 +00:00
for _, m := range s.Matchers {
if err := m.Validate(); err != nil {
return fmt.Errorf("invalid matcher: %s", err)
2015-09-27 12:25:56 +00:00
}
}
if s.StartsAt.IsZero() {
return fmt.Errorf("start time missing")
}
if s.EndsAt.IsZero() {
return fmt.Errorf("end time missing")
}
if s.EndsAt.Before(s.StartsAt) {
return fmt.Errorf("start time must be before end time")
}
if s.CreatedBy == "" {
return fmt.Errorf("creator information missing")
}
if s.Comment == "" {
return fmt.Errorf("comment missing")
}
// if s.CreatedAt.IsZero() {
// return fmt.Errorf("creation timestamp missing")
// }
return nil
2015-09-27 12:25:56 +00:00
}
// Init initializes a silence. Must be called before using Mutes.
func (s *Silence) Init() error {
for _, m := range s.Matchers {
if err := m.Init(); err != nil {
return err
}
}
sort.Sort(s.Matchers)
return nil
}
2015-09-27 12:25:56 +00:00
// Mutes implements the Muter interface.
//
// TODO(fabxc): consider making this a function accepting a
// timestamp and returning a Muter, i.e. s.Muter(ts).Mutes(lset).
func (s *Silence) Mutes(lset model.LabelSet) bool {
var now time.Time
if s.now != nil {
now = s.now()
} else {
now = time.Now()
}
if now.Before(s.StartsAt) || now.After(s.EndsAt) {
2015-10-01 15:50:15 +00:00
return false
2015-09-27 12:25:56 +00:00
}
return s.Matchers.Match(lset)
2015-09-27 12:25:56 +00:00
}
2016-08-30 12:19:22 +00:00
// Deleted returns whether a silence is deleted. Semantically this means it had no effect
// on history at any point.
func (s *Silence) Deleted() bool {
return s.StartsAt.Equal(s.EndsAt)
}