prometheus源码阅读 - 告警接收与发送

初始化

入口: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)
}

转载于:https://my.oschina.net/sannychan/blog/1600777

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值