Nginx請求日誌輸出到ELK,同時通過Elastalert監控ELK日誌中的關鍵信息(如http狀態500+錯誤,耗時較長的請求數達到閾值等等),這幾乎是中小型互聯網公司的標配。
Elastalert自帶的報警方式雖然多種多樣,但是不能實現根據報警信息分組發送,如研發人員也很關心這些指標,需要接受本項目的報警,運維需要接受所有項目的報警,報警方式要支持電話語音、短信、郵件、釘釘羣。要實現這些,只能自己擼腳本了。
1.首先從yaml配置文件開始
yunwei:
member:
zhangshan:
phone: 15895820001
mail: [email protected]
lisi:
phone: 15895820002
mail: [email protected]
dingtoken:
e802cb4b5791bb08e1bc79cfd62c0a6bae4b77e8758b4b52522d5119478f1234
project1:
member:
zhouwu:
phone: 15895820003
mail: [email protected]
wangliu:
phone: 15895820004
mail: [email protected]
dingtoken:
0a30c27cbb9bb17e5dbcb721578b7a6a490810c2fc237e1af5a1289557d31234
project2:
member:
liudehua:
phone: 15895820005
mail: [email protected]
說明:
- yunwei代表運維組;project1\porject2代表各個研發組,研發組名稱必須與elastalert中的一級域名一致(這個跟各公司的具體情況有關,我們公司有n個平臺,每個平臺有1個或多個1級域名)
- 每個組下的member可以有1-n個user;
- 每個組有一個釘釘羣;
- phone\mail\dingtoken都不是必須的,如project2沒有釘釘羣,則不發釘釘通知;
- 對於warning級別的報警,通過phone發送短信通知,對於disaster級別的通知,通過phone發送電話語音通知,所有級別的報警都會通過mail\dingtoken發送。
2.Elastalert的規則配置
以監控500狀態爲例說明配置
es_host: 10.10.10.1
es_port: 9200
name: freq-status-500
type: frequency
index: nginx-*
num_events: 30
timeframe:
minutes: 1
filter:
- bool:
must:
- terms:
status: ["500","501","502","503","504"]
use_terms_query: true
doc_type: doc
terms_size: 10
query_key:
- domain
- status
realert:
minutes: 60
alert:
- command
new_style_string_format: true
command: ["/root/elastalert-0.1.38/myalert/elastalert-alarm/alarm.py","--level=warning","--domain={domain,status}","--rulename=freq-status-500","--type=frequency","--num_events=30","--timeframe=1min"]
說明:
- 官方說可以支持多個query_key,但測試過程中發現對於frequency類型的rule,多query_key死活不成功,後來發現frequency類型下並不支持多key,需要改造(見下一章節)
- 實現按組報警,與普通Elastalert報警的主要區別在於,command要輸出很多自定義參數,腳本通過這些參數決定發送的組合發送的內容,具體含義見alarm.py腳本
parser.add_argument('--level',dest='level',help='warning, distater')
parser.add_argument('--domain',dest='domain',help='for instance: sina_www, if rule_name start with freq-500,then sina_www-500')
parser.add_argument('--rulename', dest='rulename', help='rulename')
parser.add_argument('--type', dest='type', help='frequence, flatline')
parser.add_argument('--num_events', dest='num_events', help='num_events')
parser.add_argument('--timeframe', dest='timeframe', help='timeframe')
parser.add_argument('--reqtime_gt', dest='reqtime_gt', help='request time greater than')
3.frequency類型的規則支持多字段query_key
多query_key是非常實用的,如上文中,我要監控每個域名每種HTTP 500狀態的請求數,一個rule就能實現了。可惜作者沒支持好,需要稍微改造下。
配置舉例(use_terms_query必須配置):
use_terms_query: true
query_key:
- domain
- status
修改elastalert.py中的方法get_terms_query:
修改前:
else:
aggs_query = query
aggs_query['aggs'] = {'counts': {'terms': {'field': field, 'size': size}}}
return aggs_query
修改後(暫且只支持2個字段):
else:
aggs_query = query
field_list = field.split(",")
if len(field_list) == 1:
aggs_query['aggs'] = {'counts': {'terms': {'field': field, 'size': size}}}
elif len(field_list) == 2:
source= "doc['" + field_list[0] + "'].value + '-' + doc['" + field_list[1] + "'].value"
aggs_query['aggs'] = {'counts': {'terms': {'script': {'source': source}, 'size': size}}}
else:
elastalert_logger.inof("Not support more than 2 fields in query_key")
return aggs_query
alert中獲取具體domain和status方式如下:
command: ["/tmp/alert_log.sh", "warning - freq 500 exceed, domain: {domain,status}"]
4.具體代碼
文件說明:
alarm.py --程序入口,參數解析
alert_channel.py --報警發送通道(短信、語音、郵件、釘釘羣)
alert.py --構造發送對象和消息內容
aliyunsdk_SingleCallByTtsRequest.py --阿里電話語音第三方庫
config-contact.yaml --報警對象配置文件
config.py --加載配置文件
requirements.txt --依賴
util.py --工具方法
代碼地址:https://github.com/meishd/elastalert-alarm
5.效果
如域名www.sina.com的502請求數每分鐘超過30個,則報警內容如下:
注:我們ELK中將domain改成“ 一級域名_二級域名 ”的格式入庫
warning: sina_www status of 502 exceed 30 per 1min