alertmanager源码阅读 - 启动分析

笔者使用的alertmanager版本为0.9.1,

软件地址:https://github.com/prometheus/alertmanager

初始化

关于获取命令行参数,alertmanager和prometheus不同的是,am使用原生的flag库来获取。

configFile      = flag.String("config.file", "alertmanager.yml", "Alertmanager configuration file name.")
dataDir         = flag.String("storage.path", "data/", "Base path for data storage.")

由于目前am压力还小,没有使用HA方案,基于分布式通信协议gossip的mesh及相关的功能暂时不进行深入阅读。

nlog初始化

先看下nlog的定义nflog/nflog.go

type nlog struct {
	logger    log.Logger
	metrics   *metrics
	now       func() time.Time
	retention time.Duration
	runInterval time.Duration
	snapf       string
	stopc       chan struct{}
	done        func()
	mtx sync.RWMutex
	st  gossipData
}

接下来就是nlog的初始化,[]nflog.Option中每一个返回的都是入参为nlog的方法。

notificationLogOpts := []nflog.Option{
		nflog.WithRetention(*retention),
		nflog.WithSnapshot(filepath.Join(*dataDir, "nflog")),
		nflog.WithMaintenance(15*time.Minute, stopc, wg.Done),
		nflog.WithMetrics(prometheus.DefaultRegisterer),
		nflog.WithLogger(log.Base().With("component", "nflog")),
	}
notificationLog, err := nflog.New(notificationLogOpts...)

nflog.New()会执行nflog.Option方法来最终完成nlog初始化,nflog/nflog.go

func New(opts ...Option) (Log, error) {
    l := &nlog{
		logger: log.NewNopLogger(),
		now:    utcNow,
		st:     map[string]*pb.MeshEntry{},
	}
	for _, o := range opts {
		if err := o(l); err != nil {
			return nil, err
		}
	}

    go l.run()
}

marker与silences

marker := types.NewMarker()
silenceOpts := silence.Options{
		SnapshotFile: filepath.Join(*dataDir, "silences"),
		Retention:    *retention,
		Logger:       log.Base().With("component", "silences"),
		Metrics:      prometheus.DefaultRegisterer,
	}
silences, err := silence.New(silenceOpts)

go func() {
		silences.Maintenance(15*time.Minute, filepath.Join(*dataDir, "silences"), stopc)
		wg.Done()
	}()  //每隔15分钟将silences数据写入硬盘
alerts, err := mem.NewAlerts(marker, 30*time.Minute, *dataDir)

func NewAlerts(m types.Marker, intervalGC time.Duration, path string) (*Alerts, error) {
	a := &Alerts{
		alerts:     map[model.Fingerprint]*types.Alert{},
		marker:     m,
		intervalGC: intervalGC,
		stopGC:     make(chan struct{}),
		listeners:  map[int]chan *types.Alert{},
		next:       0,
	}
	go a.runGC() //每隔30分钟将已经解决的alert删除

	return a, nil
}

api

var (
		inhibitor *inhibit.Inhibitor
		tmpl      *template.Template
		pipeline  notify.Stage
		disp      *dispatch.Dispatcher
	)
apiv := api.New(
		alerts,
		silences,
		func(matchers []*labels.Matcher) dispatch.AlertOverview {
			return disp.Groups(matchers)
		},
		marker.Status,
		mrouter,
	)
	apiv.SetMarker(marker)
    apiv.Register(router.WithPrefix("/api")) //在api的uri增加/api前缀

配置

定义了reload方法来进行读取配置和启动相关的方法,并进行reload的首次调用

reload := func() (err error) {
    conf, plainCfg, err := config.LoadFile(*configFile)
    err = apiv.Update(conf, time.Duration(conf.Global.ResolveTimeout))
    inhibitor = inhibit.NewInhibitor(alerts, conf.InhibitRules, marker)
		pipeline = notify.BuildPipeline(
			conf.Receivers,
			tmpl,
			waitFunc,
			inhibitor,
			silences,
			notificationLog,
			marker,
		)
		disp = dispatch.NewDispatcher(alerts, dispatch.NewRoute(conf.Route, nil), pipeline, marker, timeoutFunc)
		go disp.Run()
		go inhibitor.Run()
}

if err := reload(); err != nil {
		os.Exit(1)
	}

更新配置

定义webReload chan,使用其阻塞机制,在调用reload的api时,或者向进程发送SIGHUP信号进行reload()操作

webReload := make(chan struct{})
ui.Register(router, webReload)
var (
		hup      = make(chan os.Signal)
		hupReady = make(chan bool)
		term     = make(chan os.Signal)
	)
	signal.Notify(hup, syscall.SIGHUP)
	signal.Notify(term, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-hupReady
		for {
			select {
			case <-hup:   //接收SIGHUP信号
			case <-webReload: //api接口调用时会向此chan写入数据
			}
			reload()
		}
	}()

api更新的接口代码

ui/web.go

r.Post("/-/reload", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("Reloading configuration file..."))
		reloadCh <- struct{}{}
	})

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

<think>我们正在排查Prometheus监控系统通过钉钉媒介发送告警失败的问题。根据用户描述,所有组件都是源码安装,配置正确,且钉钉机器人设置了加签但没有自定义关键词。测试时邮箱告警正常,但钉钉没有收到告警。我们需要从多个层面进行排查,并配置生成详细的dingtalk和Alertmanager日志以辅助诊断。 ## 问题排查步骤 ### 1. 验证钉钉机器人配置 - **加签处理**:钉钉机器人开启了加签,那么`config.yml`中的URL必须包含动态生成的`timestamp`和`sign`参数。确保在配置文件中正确计算了签名。签名生成方法如下: ```bash # 生成签名示例(在服务器上执行) timestamp=$(date +%s000) secret="你的加签密钥" sign=$(echo -n "${timestamp}\n${secret}" | openssl dgst -sha256 -hmac "$secret" -binary | base64 | tr -d '\n') # 最终的URL应该是:https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&timestamp=$timestamp&sign=$sign ``` 在`config.yml`中配置的`ddurl`必须包含这两个参数。 - **IP白名单**:检查钉钉机器人的IP白名单设置,确保运行`prometheus-webhook-dingtalk`服务的服务器公网IP已加入白名单。 ### 2. 检查网络连通性 在服务器上测试钉钉API的可达性: ```bash # 使用curl测试钉钉API curl -v -X POST -H "Content-Type: application/json" \ -d '{"msgtype":"text","text":{"content":"[网络测试] 直接访问钉钉API"}}' \ "https://oapi.dingtalk.com/robot/send?access_token=你的access_token&timestamp=时间戳&sign=签名" ``` 注意:将`access_token`、`timestamp`和`sign`替换为实际值。如果返回`{"errcode":0}`表示网络正常,否则根据错误码排查: - 310000:Token无效 - 130101:签名错误 - 连接超时:检查服务器防火墙或安全组是否放行443端口出站 ### 3. 检查Alertmanager与钉钉服务对接 - **Alertmanager配置**:确保`alertmanager.yml`中`receivers`部分正确指向钉钉服务的地址(即`prometheus-webhook-dingtalk`服务监听的地址和端口,默认为8060): ```yaml receivers: - name: 'dingding' webhook_configs: - url: 'http://localhost:8060/dingtalk/webhook1/send' # 注意路径/webhook1根据实际配置 send_resolved: true ``` 使用`amtool`检查配置: ```bash amtool check-config alertmanager.yml ``` - **端口监听状态**:确认钉钉服务(8060端口)正在运行: ```bash netstat -tunlp | grep 8060 ``` ### 4. 启用详细日志 #### 配置Alertmanager日志级别 修改Alertmanager启动参数,增加日志级别为`debug`。如果使用systemd管理服务,编辑`/etc/systemd/system/alertmanager.service`: ```ini [Service] ExecStart=/usr/local/bin/alertmanager \ --config.file=/etc/alertmanager/alertmanager.yml \ --storage.path=/data/alertmanager \ --log.level=debug # 增加这一行 ``` 重启服务并跟踪日志: ```bash systemctl daemon-reload systemctl restart alertmanager journalctl -u alertmanager -f ``` #### 配置钉钉服务日志级别 `prometheus-webhook-dingtalk`服务启动时添加`--log.level=debug`参数。同样编辑systemd服务文件: ```ini [Service] ExecStart=/usr/local/bin/prometheus-webhook-dingtalk \ --web.listen-address=":8060" \ --config.file=/etc/prometheus-webhook-dingtalk/config.yml \ --log.level=debug # 增加这一行 ``` 重启服务并查看日志: ```bash systemctl daemon-reload systemctl restart prometheus-webhook-dingtalk journalctl -u prometheus-webhook-dingtalk -f ``` ### 5. 触发测试告警 使用`curl`命令模拟告警发送到Alertmanager: ```bash curl -X POST http://localhost:9093/api/v1/alerts -d '[{ "labels": {"alertname":"TestAlert", "instance":"localhost:9100"}, "annotations": {"summary": "钉钉告警测试"}, "generatorURL": "http://localhost:9090/graph?g0.expr=up+%3D%3D+0" }]' ``` 观察Alertmanager日志和钉钉服务日志中的错误信息。 ### 6. 常见错误及解决 - **签名错误**:钉钉服务日志中会出现`invalid sign`错误。重新计算签名,确保`timestamp`是毫秒级时间戳(如`date +%s000`),且签名计算正确。 - **模板渲染失败**:钉钉服务日志中提示模板错误。简化模板测试,例如在`config.yml`中使用: ```yaml template: | {{ define "dinglink.text" }}[Prometheus告警]{{ .CommonAnnotations.summary }}{{ end }} ``` - **端口冲突**:如果8060端口被占用,修改钉钉服务监听端口(如改为8061),并同步更新`alertmanager.yml`中的URL。 ## 生成日志的关键步骤总结 1. **修改服务配置**:在systemd服务文件中增加`--log.level=debug`参数。 2. **重启服务**:使用`systemctl restart`重启服务。 3. **跟踪日志**:使用`journalctl -u 服务名 -f`实时查看日志。 4. **触发测试告警**:通过API发送测试告警,观察日志输出。 ## 相关问题 1. 如何验证Prometheus与Alertmanager的连通性? 2. 钉钉机器人消息如何添加自定义格式(如Markdown)? 3. Alertmanager如何实现告警去重和分组? 4. 如何监控Prometheus自身的健康状态? [^1]: PrometheusAlert钉钉配置参考 [^2]: Prometheus配置Alertmanager</think>## Prometheus钉钉告警未接收问题排查与日志配置指南 ### 一、核心问题排查步骤 #### 1. 钉钉机器人签名验证(首要检查) ```bash # 生成签名验证脚本(替换your_secret) timestamp=$(date +%s000) secret="your_secret" sign=$(echo -n "${timestamp}\n${secret}" | openssl dgst -sha256 -hmac "$secret" -binary | base64) echo "验证URL: https://oapi.dingtalk.com/robot/send?access_token=XXX&timestamp=$timestamp&sign=$sign" ``` **检查点**: - 确保`config.yml`中的URL包含动态生成的`timestamp`和`sign`参数 - 服务器时间同步:`timedatectl status`(误差需在±1分钟内) - 机器人IP白名单:将Alertmanager服务器公网IP加入钉钉控制台 #### 2. 网络连通性测试 ```bash # 测试钉钉API可达性 curl -v -X POST -H "Content-Type: application/json" \ -d '{"msgtype":"text","text":{"content":"[TEST] 网络连通性测试"}}' \ "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN&timestamp=$timestamp&sign=$sign" # 测试本地webhook服务 curl -X POST http://localhost:8060/dingtalk/webhook1/send \ -H 'Content-Type: application/json' \ -d '{"text": {"content": "服务连通性测试"}}' ``` **错误码解析**: - `{"errcode":310000}` → Token无效 - `{"errcode":130101}` → 签名错误 - 连接超时 → 检查防火墙:`sudo ufw status` #### 3. Alertmanager配置验证 检查`alertmanager.yml`关键配置: ```yaml route: receiver: 'dingding-receiver' # 必须与receivers名称一致 receivers: - name: 'dingding-receiver' webhook_configs: - url: 'http://localhost:8060/dingtalk/webhook1/send' send_resolved: true http_config: timeout: 5s # 避免阻塞 ``` 验证配置: ```bash amtool check-config alertmanager.yml ``` ### 二、日志配置方法 #### 1. Alertmanager日志配置(systemd服务) ```ini # /etc/systemd/system/alertmanager.service [Service] ExecStart=/usr/local/bin/alertmanager \ --config.file=/etc/alertmanager/alertmanager.yml \ --storage.path=/data/alertmanager \ --log.level=debug # 启用debug日志 ``` 重启并查看日志: ```bash sudo systemctl daemon-reload sudo systemctl restart alertmanager journalctl -u alertmanager -f -o cat | grep 'webhook' ``` #### 2. Dingtalk Webhook日志配置 ```ini # /etc/systemd/system/prometheus-webhook-dingtalk.service [Service] ExecStart=/usr/local/bin/prometheus-webhook-dingtalk \ --web.listen-address=":8060" \ --config.file=/etc/prometheus-webhook-dingtalk/config.yml \ --log.level=debug # 启用详细日志 ``` 启用日志跟踪: ```bash sudo systemctl restart prometheus-webhook-dingtalk journalctl -u prometheus-webhook-dingtalk -f ``` #### 3. 关键日志分析- **Alertmanager日志**:搜索`webhook=dingding`查看转发状态 - **Dingtalk日志**:检查`Received alert`条目和API响应 - 常见错误日志: ``` level=error msg="Error sending notification" integration=webhook error="unexpected status code 403" level=warn msg="Got response status" status=130101 ``` ### 三、端到端测试流程 ```mermaid sequenceDiagram participant P as Prometheus participant A as Alertmanager participant D as Dingtalk服务 participant R as 钉钉API P->>A: 触发告警(测试规则) A->>D: POST告警到8060端口 D->>R: 调用钉钉API(带签名) R-->>D: 返回响应(errcode) D-->>A: HTTP状态码 A->>P: 记录处理结果 ``` 测试命令: ```bash # 1. 触发测试告警 curl -X POST http://localhost:9093/api/v1/alerts -d '[{ "labels": {"alertname":"TestAlert","instance":"localhost:9100"}, "annotations": {"summary":"钉钉通路测试"} }]' # 2. 检查日志链 tail -f /var/log/alertmanager.log | grep 'TestAlert' tail -f /var/log/webhook-dingtalk.log | grep 'TestAlert' ``` ### 四、常见问题解决方案 | 问题现象 | 解决方案 | |-------------------------|--------------------------------------------------------------------------| | 签名验证失败 | 重新生成签名,确保URL包含动态`timestamp`和`sign`参数 | | 连接超时(443端口) | 开放出站规则:`sudo ufw allow out 443/tcp` | | HTTP 403错误 | 检查IP白名单,将服务器公网IP加入钉钉控制台 | | 模板渲染错误 | 简化模板:`{{ define "dingtalk.text" }}[Prometheus] {{ .CommonAnnotations.summary }}{{ end }}` | | 服务未启动 | 检查端口监听:`netstat -tunlp | grep 8060` | > **终极验证**:直接在服务器调用钉钉服务: > ```bash > curl -XPOST http://localhost:8060/dingtalk/webhook1/send \ > -d '{"msgtype":"text","text":{"content":"[BYPASS] 最终验证"}}' > ``` > 若钉钉收不到,问题在钉钉配置;若收到,问题在Alertmanager链路。 ### 五、日志分析技巧 1. **Alertmanager成功转发标志**: ``` level=debug msg="Doing request" url=http://localhost:8060/dingtalk/webhook1/send level=debug msg="Response status" status=200 ``` 2. **钉钉服务错误示例**: ``` level=error msg="Failed to send notification" error="dingtalk error: 130101" level=warn msg="Invalid request signature" ``` 3. **网络问题诊断**: ``` level=error msg="Failed to send notification" error="Post \"https://oapi.dingtalk.com/...\": context deadline exceeded" ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值