初始化
入口:cmd/prometheus/main.go
notifier = notifier.New(&cfg.notifier, log.With(logger, "component", "notifier"))
go notifier.Run()
在Run方法中启动for循环:
for {
select {
case <-n.ctx.Done():
return
case <-n.more:
}
}
接下来就是ApplyConfig()方法去读取配置
for _, cfg := range conf.AlertingConfig.AlertmanagerConfigs {
ams, err := newAlertmanagerSet(cfg, n.logger) //根据配置初始化AlertmanagerSet
}
for _, ams := range amSets {
go ams.ts.Run(ctx) //启动AlertmanagerSet
}
启动完成,就等待接收alert,而alert发送到notifier地方在rules/manager.go
if ar, ok := rule.(*AlertingRule); ok {
g.sendAlerts(ar)
}
func (g *Group) sendAlerts(rule *AlertingRule) error {
if len(alerts) > 0 {
g.opts.Notifier.Send(alerts...)
}
}
当告警规则执行后,满足规则条件后会向notifier发送一条alert。
接收
回到notifier/notifier.go的Send()方法:
func (n *Notifier) Send(alerts ...*Alert) {
for _, a := range alerts {
lb := labels.NewBuilder(a.Labels)
}
alerts = n.relabelAlerts(alerts)
if d := len(alerts) - n.opts.QueueCapacity; d > 0 { //如果当前批次的alerts数量大于queue的容量,只取其中容量那么多的alert
alerts = alerts[d:]
}
if d := (len(n.queue) + len(alerts)) - n.opts.QueueCapacity; d > 0 { //如果alerts数量加queue当前大小大于queue容量,去掉queue中多余的alerts
n.queue = n.queue[d:]
}
n.queue = append(n.queue, alerts...)
n.setMore()
}
发送
回到notifier/notifier.go的Run(),这里面使用for-select-chan阻塞机制,在接收时向more chan写入数据
func (n *Notifier) Run() {
for {
select {
case <-n.ctx.Done():
return
case <-n.more:
}
alerts := n.nextBatch() //取出一次需要发送的alerts数据
if !n.sendAll(alerts...) {
n.metrics.dropped.Add(float64(len(alerts))) //如果发送失败,dropped指标数据累加
}
// If the queue still has items left, kick off the next iteration.
if n.queueLen() > 0 {
n.setMore()
}
}
}
接下看sendAll方法,将alerts转换为json
func (n *Notifier) sendAll(alerts ...*Alert) bool {
b, err := json.Marshal(alerts)
amSets := n.alertmanagers
for _, ams := range amSets {
for _, am := range ams.ams {
go func(am alertmanager) {
u := am.url().String() //调用的接口地址是:http://alertmanager:3806/api/v1/alerts
n.sendOne(ctx, ams.client, u, b)
}
}
}
}
真正发送是在sendOne()方法:
func (n *Notifier) sendOne(ctx context.Context, c *http.Client, url string, b []byte) error {
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
req.Header.Set("Content-Type", contentTypeJSON)
resp, err := n.opts.Do(ctx, c, req)
}