prometheus发送alert的接口:/api/v1/alerts,初始化代码在api/api.go
func (api *API) Register(r *route.Router) {
r.Post("/alerts", ihf("add_alerts", api.addAlerts))
}
func (api *API) addAlerts(w http.ResponseWriter, r *http.Request) {
var alerts []*types.Alert
if err := receive(r, &alerts); err != nil { //
respondError()
return
}
api.insertAlerts(w, r, alerts...)
}
func (api *API) insertAlerts(w http.ResponseWriter, r *http.Request, alerts ...*types.Alert) {
now := time.Now()
for _, alert := range alerts {
alert.UpdatedAt = now
if alert.EndsAt.IsZero() {
alert.Timeout = true
alert.EndsAt = now.Add(api.resolveTimeout) //如果resolveTimeout后alert没有更新,alert会被标记为resolved,默认的resolveTimeout为5m
numReceivedAlerts.WithLabelValues("firing").Inc()
} else {
numReceivedAlerts.WithLabelValues("resolved").Inc()
}
}
var (
validAlerts = make([]*types.Alert, 0, len(alerts))
validationErrs = &types.MultiError{}
)
for _, a := range alerts {
if err := a.Validate(); err != nil {
continue
}
validAlerts = append(validAlerts, a)
}
if err := api.alerts.Put(validAlerts...); err != nil {
}
}
接下来我们看看alerts.Put(),这是一个接口方法,目前的版本只有mem实现方式,代码在:provider/mem/mem.go
func (a *Alerts) Put(alerts ...*types.Alert) error {
for _, alert := range alerts {
fp := alert.Fingerprint()
if old, ok := a.alerts[fp]; ok {
if (alert.EndsAt.After(old.StartsAt) && alert.EndsAt.Before(old.EndsAt)) ||
(alert.StartsAt.After(old.StartsAt) && alert.StartsAt.Before(old.EndsAt)) {
alert = old.Merge(alert)
}
}
a.alerts[fp] = alert
for _, ch := range a.listeners {
ch <- alert
}
}
}
接收alert的最终去向是向ch chan写入了数据,我们再来看看此处的ch是如何来的。
ch 是循环listeners,再追溯listeners的来源,就是provider/mem/mem.go的Subscribe()方法。
func (a *Alerts) Subscribe() provider.AlertIterator {
var (
ch = make(chan *types.Alert, 200)
done = make(chan struct{})
)
a.listeners[i] = ch
return provider.NewAlertIterator(ch, done, err)
}
而调用Subscribe()有两处
- Dispatcher
用于告警的group,router管理,满足条件情况下发送alert。后面有专门的帖子来分析这一块。
func (d *Dispatcher) Run() {
d.run(d.alerts.Subscribe())
}
- Inhibitor
Inhibitor主要是用于针对两个告警,如果他们在某些指定的属性不同、某些指定的属性相同的情况下,只发送其中某属性为某值的告警。 比如cpu使用率的告警,在90%时为critical,75%时为warning;可以设置Inhibitor规则,让warning告警不发送出来。 笔者在使用过程中,尚未使用Inhibitor的规则。
func (ih *Inhibitor) Run() {
it := ih.alerts.Subscribe()
}