在调研elastalert时几乎把整个源码都看了一遍,记录一下几个重要的部分.
核心查询
rule文件配置的filter,最终都会转换成es底层支持的格式, 核心代码如下:
1 | def get_query(filters, starttime=None, endtime=None, sort=True, timestamp_field='@timestamp', to_ts_func=dt_to_ts, desc=False, |
最终转换成的格式如下, 如果查询的结果与期望值不一样,也可以生产的此语句进行排查.
1 | curl -H 'Content-Type: application/json' -XGET 'http://localhost:9200/demo.demo-*/_search?pretty&_source_include=%40timestamp%2C%2A&ignore_unavailable=true&scroll=30s&size=10000' -d '{ |
match_body
num_hits vs num_matches
1 | num_hits is the number of documents returned by elasticsearch for a given query. num_matches is how many times that data matched your rule, each one potentially generating an alert. |
写回到es索引:elastalert_status
同样,产生的告警的现场日志在发送到告警介质后都会写入到es索引中
1 | def send_alert(self, matches, rule, alert_time=None, retried=False): |
starttime/endtime/original_time
endtime一般都是执行查询时取的当前时间,因此elastalert默认没有保存,starttime一般是由endtime减去timeframe计算而来,但是如果elastalert重启的话, starttime会跟期望的不太一样,通过源码可以看到还有一个original_time, original_time为存在在es中的上一次执行的endtime, 因此,每次查询的时候,都会从original_time处开始查询, endtime为当前时间
因此starttime最好设置为original_time,使用starttime有产生歧义
1 | body = {'rule_name': rule['name'], |
当然为了避免elastalert重启时离上次运行的时间间隔太久, 默认情况下启动后会从es中读取starttime
,以这个时间点到当前时间为时间窗口,然后以run_every给定的时间进行查询,所以,在这种情况下可能会出现刚重启时就出现大量的查询,很多时间太久的历史日志监控是无意义,因此可以在elastalert.yaml中指定old_query_limit: minutes: 1
来限定starttime为当前时间的前一分钟.
enhancement
elastalert提供两种方案可以让在找到匹配项后立即运行增强功能(run_enhancements_first)或者在发送告警前进行操作,比如修改match操作(match_enhancements)
run_enhancements_first
如果在rule配置中指定的了run_enhancements_first,源码如下:
1 | def run_rule(self, rule, endtime, starttime=None): |
match_enhancements
1 | def send_alert(self, matches, rule, alert_time=None, retried=False): |
很多人关心的elastalert没有保存的endtime字段,其实就可以match_enhancements中添加字段.
自定义告警
自定义邮件格式
由于默认的邮件告警只是简单的把str格式的内容通过邮件发送出去,非常不美观,因此通过jinja2的形式自定义了邮件格式
首先在rule配置中定义email_format: html
由于只是在发送邮件的时候才使用jinja2的html模板,因此需要对alert
的类型进行判断
修改的源码如下:
1 | class BasicMatchString(object): |
由于所有的告警类型的基类都是Alerter
,因此通过这个来传递告警类型.
1 | class Alerter(object): |
这样就完成自定义邮件格式了,模板如下:
字段直接在rule文件中alert_text_args中传入即可.
微信报警
elastalert本身支持自定义的告警接入,只需要实现 body = self.create_alert_body(matches)
方法即可.不难,难点在于企业微信api如何使用, 代码参考elastalert-wechat-plugin, 亲测可用.
问题
- 如果修改源码后rule执行出现问题, 则会自动地生成exception写入到索引中且该rule会被disable掉,直到不再报错之前都不再执行.
1 | 03:18:59.552Z ERROR elastalert-server: |
- es中的until字段记录了下次执行的时候(由apscheduler框架支持)
1 | { |