#dingding #alerting #kafka #caddy #钉钉报警

日志报警:通过钉钉实时通报业务错误

摘要

线上服务产生报错日志,可以第一时间通知到相关的人员可以更快得修复问题,提高服务的可用性。前一篇文件已经实现把所有日志文件收集起来,于是在此只需要获取这份数据,按需要来报警。

前言

千辛万苦把所有的日志收集起来,为的就是此时。前面已经实现了把日志收集到 kafka使用 filebeat 收集日志到 kafka

写了一个小小的项目 gladmo/alerting 来实消费 kafka 中的日志文件,匹配中需要的字段时行报警。

当前项目的一些小功能:

  • 可为不同项目设置不同报警方式
  • 有其它渠道报警的,可自行编写,扩展性高
  • 聚合同类型(每 2s/每 20 个)报警

配置说明

配置示例:

[kafka]
host = ["you-kafka-host:9092"]
group = "log-collect-group"
topic = ["log-collect"]

[template]
[template.common]
    AccessToken = "47556dea1ece1536fcb069a44a391a443333ff2bb22ed6c120f2c8ff137a594a"
    AtMobiles = ["1588888888"]
    Fields = ["test.hao.0 as test", "haha"]

[alerting]
[alerting.log]
    type = "dingding"
    Template = "template.common"
[alerting.alerting]
    type = "dingding"
    Template = "template.common"

其中 [kafka] 块配置了 kafka 的基础信息,需要的有服务器的地址,消费组,需要消费的 topic 列表。

[template] 块可以创建一些公用的配置,在 [alerting] 块使用 Template = "template.common" 引入。

template 中可以配置 AccessTokenAtMobilesFields 字段,分别是钉钉的机器人 token、需要@的用户手机号、需要报警的其它字段。当前报警会报警 json 中的 ts level msg title 字段,如有其它字段需要报警,可使用 Fields字段进行配置。

[alerting] 块配置了需要报警的哪些服务, 比如 [alerting.log]log 为项目名,一般对应被收集日志文件的父目录名。

项目结构简介

├── Dockerfile
├── LICENSE
├── README.md
├── alerting.go
├── config.toml 		// 项目配置文件
├── conf 				// 配置文件处理
├── consumer			// 消费日志
├── inbox				// 消息处理
├── log 				// 打印日志
├── notice				// 通知渠道及规则
│   ├── channels		// 通知方式,目前只有钉钉
│   │   └── dingding 	// 钉钉通知方式实现
│   └── rule			// 配置规则处理
└── vendor				// 依赖

项目中需要的配置在 config.toml 中进行配置,如需要通知其它渠道的,可以自行在 notice/channels 中添加实现,基础的数据类型已经在 BaseInfo 结构体中有定义,可以拿到要通知的消息以及一些附属字段。同时欢迎 PR。

核心代码简介

inbox/inbox.go:

func Dispatch() {
	// handle message
	for line := range ch {

		// Get project name from log path.
		project := getProjectName(line.LogPath)

		// get noticer by project name
		projectRule, err := rule.GetNoticer(project)
		if err != nil {
			// todo new default noticer, notice warn and error.
			log.Logger.Info(err.Error())
			continue
		}

		if _, ok := projectRule.Levels[line.Level]; !ok {
			continue
		}

		// New alerting
		alert := &notice.Alerting{
			Project: project,
			Message: line.Message,
			Level:   line.Level,
			Count:   1,
			Noticer: projectRule.Noticer,
		}

		notice.Push(alert)
	}
}

// getProjectName 输入 /usr/share/filebeat/logs/log.log 返回 logs
func getProjectName(p string) (project string) {
	return filepath.Base(filepath.Dir(p))
}

这里的 ch 这个全局 channel 是由 consumer 负责把 kafka 中的数据消费整理后写到这里的。

随后根据日志文件的数据,获取项目名,使用项目名从配置文件中获取项目的报警配置。如未找到,则忽略此条消息。这里返回的主要结构是一个实现了 Noticer 的一个结构体,当前只实现了钉钉,有其它报警渠道的可以实现这个 interface 便可以配置到配置文件中去,实现其它的报警渠道就是这么简单。

当前消息的报警级别不在配置的报警级别中的,忽略此条消息。注:未配置报警级别的默认 error

鉴权完毕后,组装一个 notice.Alerting 的结构体 push 到一个聚合队列中,在这里实现 2s 或 20个一组进行报警。

效果一览

效果效果

小结

能主动推送日志产生的问题,这感觉太好了,我要把更多的项目接入到这里面来。

接入更多的项目,增加更多的功能。

Author Mo 最后更新: 2019-04-29 01:00:41