文章目录
- 前言
- [一、ElastAlert 概览](#一、ElastAlert 概览)
-
- [1.1 简介](#1.1 简介)
- [1.2 ElastAlert 特性](#1.2 ElastAlert 特性)
- [二、ElastAlert 下载部署](#二、ElastAlert 下载部署)
-
- [2.1 安装 Python3 环境](#2.1 安装 Python3 环境)
- [2.2 下载 ElastAlert](#2.2 下载 ElastAlert)
- [2.3 部署 ElastAlert](#2.3 部署 ElastAlert)
- 三、接入平台
-
- [3.1 对外接口层](#3.1 对外接口层)
- [3.2 服务层](#3.2 服务层)
前言
ElastAlert 是 Yelp 公司基于 python 开发的 ELK 日志告警插件,Elastalert 通过查询 Elasticsearch 中的记录与定于的告警规则进行对比,判断是否满足告警条件。发生匹配时将为该告警触发一个或多个告警动作。告警规则由 ElastAlert 的 rules 定义,每个规则定义一个查询。
一、ElastAlert 概览
1.1 简介
ElastAlert 程序的设计是可靠的、高度可定制的、安装方面也是简单的并且可配置的。
它通过将 Elasticsearch 与两个组件,规则类型(rule types)以及警报(alerts)相结合进行实现。Elasticsearch 会定期的被程序查询,得出的数据经由规则类型(rule type)确定何时找到了匹配项。当找到匹配项后,会根据匹配的数据结果给出一个或多个警报。
配置方面是由一组规则(rules)进行管控,每个规则(rules)里面定义了一个查询,一个规则类型以及一组警报。
目前支持以下的报警类型:
- Command
- JIRA
- OpsGenie
- SNS
- HipChat
- Slack
- Telegram
- Debug
- Stomp
1.2 ElastAlert 特性
- 架构简单,定制灵活
- 支持多种匹配规则(频率、阈值、数据变化、黑白名单、变化率等)
- 支持多种警报类型(邮件、HTTP POST、自定义脚本等)
- 匹配项汇总报警,重复警报抑制,报警失败重试和过期
- 可用性强,状态信息保存到Elasticsearch的索引中
二、ElastAlert 下载部署
2.1 安装 Python3 环境
切换到 /data 目录下
bash
cd /data
安装 openssl
bash
yum -y install wget openssl openssl-devel gcc gcc-c++
下载 Python 安装包
bash
wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz
解压缩
bash
tar -zxvf Python-3.6.9.tgz
cd Python-3.6.9 目录
bash
cd Python-3.6.9
安装配置
bash
./configure
编译
bash
make && make install
建立软连接去除系统自带的 Python2
bash
mv /usr/bin/python /usr/bin/python_old
ln -s /usr/local/python/bin/python3 /usr/bin/python
ln -s /usr/local/python/bin/pip3 /usr/bin/pip
pip install --upgrade pip
查看版本
bash
[root@boe-dc-38 bin]# python -V
Python 3.6.9
[root@boe-dc-38 bin]# pip -V
pip 21.3.1 from /usr/local/python/lib/python3.6/site-packages/pip (python 3.6)
2.2 下载 ElastAlert
1.克隆 ElastAlert 项目
bash
git clone https://github.com/Yelp/elastalert.git
2.安装
bash
cd elastalert
pip install elasticsearch>=7.0.0
pip install -r requirements.txt
python setup.py install
3.安装成功后可以看到四个命令
bash
[root@boe-dc-38 bin]# ll /usr/local/python/bin/elastalert*
-rwxr-xr-x 1 root root 396 Nov 17 13:40 /usr/local/python/bin/elastalert
-rwxr-xr-x 1 root root 422 Nov 17 13:40 /usr/local/python/bin/elastalert-create-index
-rwxr-xr-x 1 root root 430 Nov 17 13:40 /usr/local/python/bin/elastalert-rule-from-kibana
-rwxr-xr-x 1 root root 416 Nov 17 13:40 /usr/local/python/bin/elastalert-test-rule
4.软连接到 /usr/bin 下,方便使用
bash
ln -s /usr/local/python/bin/elastalert* /usr/bin
- elastalert 报警执行的命令,会根据报警规则执行相应操作。
- elastalert-create-index 会创建一个索引,ElastAlert 会把执行记录存放到这个索引中,默认情况下,索引名叫 elastalert_status。其中有 4 个 _type,都有自己的 @timestamp 字段,所以同样也可以用 Kibana 来查看这个索引的日志记录情况。
- elastalert-rule-from-kibana 从 Kibana3 已保存的仪表盘中读取 Filtering 设置,帮助生成config.yaml 里的配置。不过注意它只会读取 filtering,不包括 queries。
- elastalert-test-rule 测试自定义配置中的 rule 设置。
5.创建 elastalert 索引
bash
elastalert-create-index
2.3 部署 ElastAlert
1.主配置文件config.yaml
yaml
#加载rule的目录,默认是example_rules
rules_folder: /data/elastalter/example_rules
#设置定时向elasticsearch发送请求,也就是告警频率
run_every:
minutes: 1
#用来设置请求里时间字段的范围
buffer_time:
minutes: 15
#elasticsearch的ip地址和端口
es_host: 192.168.136.123
es_port: 9200
#elastalert产生的日志在elasticsearch中的创建的索引
writeback_index: elastalert_status
writeback_alias: elastalert_alerts
:1
#失败重试的时间限制
alert_time_limit:
days: 2
2.邮件告警配置
bash
python -m elastalert.elastalert --verbose --config /data/elastalter/config.yaml --rule /data/elastalter/example_rules/visual-chart.yaml
三、接入平台
3.1 对外接口层
java
@Slf4j
@RestController
@RequestMapping("/webhook")
public class WebhookController {
@Autowired
WebhookService webhookService;
/**
* 接收elastalert告警消息
*
* @param request
* @return
*/
@RequestMapping("/elastalert")
public Result elastalert(HttpServletRequest request) throws IOException {
//设置流的编码
request.setCharacterEncoding("UTF-8");
StringBuffer data = new StringBuffer();
String line = null;
BufferedReader reader = null;
reader = request.getReader();
while (null != (line = reader.readLine())) {
data.append(line);
}
String result = data.toString().replace("@timestamp","timestamp");
ElastalertAlarmMessageDTOS elastalertAlarmMessageDTOS = JSON.parseObject(result, ElastalertAlarmMessageDTOS.class);
String jsonFlatten = JsonFlatten.jsonFlatten(elastalertAlarmMessageDTOS.getLog());
elastalertAlarmMessageDTOS.setLog(jsonFlatten);
log.info("请求数据===================>" + elastalertAlarmMessageDTOS);
webhookService.handleElastalert(elastalertAlarmMessageDTOS);
return Result.success();
}
}
3.2 服务层
java
/**
* 处理Elastalert消息
*
* @param alarmMessages 告警消息
*/
public void handleElastalert(ElastalertAlarmMessageDTOS alarmMessages) {
String subject = String.format(MailConstants.ELASTALERT_SUBJECT_TEMPLATE, alarmMessages.get_index());
String content = String.format(MailConstants.ELASTALERT_CONTENT_TEMPLATE_LARD, alarmMessages.get_index(),
alarmMessages.get_index(), alarmMessages.getTimestamp(), alarmMessages.getLog(),
alarmMessages.getMessage(), alarmMessages.get_id());
try {
msgService.sendLark(subject, content);
} catch (Exception e) {
log.error("发送错误日志告警通知异常, 主题:{}, 内容:{}", subject, content);
}
String indexName = serviceService.serviceName(alarmMessages.get_index());
// 获取服务名称
String serviceName = getServiceName(indexName);
// 根据服务名获取服务信息
TService service = serviceService.findByName(serviceName);
if (service == null) {
log.warn("处理Elastalert告警信息失败, 原因:未找到对应服务信息, 服务名称:{}", serviceName);
}
TElastalertAlarmRecord alarmRecord = new TElastalertAlarmRecord();
alarmRecord.setAlarmTime(alarmMessages.getTimestamp().toString());
alarmRecord.setBuId(service.getBuId());
alarmRecord.setPath(alarmMessages.getLog());
alarmRecord.setServiceName(serviceName);
alarmRecord.setAlarmMessage(alarmMessages.getMessage());
alarmRecordService.save(alarmRecord);
// 查找该BU关联的用户
List<TUser> users = userService.findByBuId(service.getBuId());
users.removeIf(user -> MailConstants.WARN_SKIP_USERS.contains(user.getEmpNo()));
if (CollectionUtils.isEmpty(users)) {
log.warn("发送Elastalert告警通知邮件失败, 原因:未找到对应的负责人, 服务名称:{}", serviceName);
}
String[] to = users.stream().map(TUser::getEmail).collect(Collectors.toList()).toArray(new String[0]);
String contentMail = String.format(MailConstants.ELASTALERT_CONTENT_TEMPLATE_LARD_MAIL, alarmMessages.get_index(),
alarmMessages.get_index(), alarmMessages.getTimestamp(), alarmMessages.getLog(),
alarmMessages.getMessage(), alarmMessages.get_id());
try {
msgService.sendHTMLMail(to, null, subject, contentMail);
} catch (Exception e) {
log.error("发送Elastalert告警通知邮件异常, 收件人:{}, 主题:{}, 内容:{}", to, subject, content);
}
}