Watcher是对Elasticsearch进行告警和通知的插件,可以根据数据的变化采取行动。它的设计原理是在Elasticsearch中执行查询,满足条件的情况下,产生告警。简单地定义查询、设置限定条件、设置预定计划和将要进行的操作后,Watcher会自动完成剩下的操作。
1.1.1 安装
Watcher是以Elasticsearch插件的形式存在的。所以安装的过程和插件安装基本一致。
安装步骤:
1) 在Elasticsearch中安装Watcher插件。
bin/plugin install license
bin/plugin install watcher
2) 权限设置,在安装watcher的时候会提示额外权限说明如下:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: plugin requires additional permissions @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.lang.RuntimePermission getClassLoader
* java.lang.RuntimePermission setContextClassLoader
* java.lang.RuntimePermission setFactory
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.
Continue with installation? [y/N]y
3) 如果在Elasticsearch中设置了禁止自动创建索引的设置,需要在配置文件中添加如下设置:action.auto_create_index: .watches,.triggered_watches,.watcher-history*
4) 启动Elasticsearch
bin/elasticsearch
5) 验证是否安装成功
GET http://localhost:9200/_watcher/stats?pretty
返回内容为:
{
"watcher_state": "started",
"watch_count": 0,
"execution_thread_pool": {
"queue_size": 0,
"max_size": 0
}
}
1.1.2 结构
一个watch的配置主要包括trigger, input, condition, actions几个部分构成,此外,在执行actions之前,您可以定义transforms过程中处理告警中的内容。
参数 | 描述 |
Trigger | 确定什么时候告警进行检查,一个告警中至少有一个Trigger |
Input | 将数据加载到告警中的内容。如果没有指定输入,则加载一个空的内容。 |
Condition | 控制是否执行告警操作。如果没有指定条件,条件默认总是执行。 |
Transform | 您可以定义在监视级别上的转换,也可以定义特定于动作的转换,可选条件。 |
Actions | 指定当告警条件被满足时会发生的动作。 |
表格9.1 结构说明
Trigger
每个告警必须有一个触发器,用来定义开始执行的时间点。每当创建一个触发器时,这个触发器被注册到一个合适的触发器引擎中。所有的触发器都是基于时间的类型。
时间触发器用系统时钟来确定当前的时间。所以要确保正确的触发预期时,需要同步所有节点上的时钟。系统提供以下几种类型的触发器类型:
hourly、daily、weekly、monthly、yearly、cron、interval
l hourly小时时刻表:
小时时刻表可以指定每小时执行一个计划,可以设置每小时的几分钟开始执行,如果不这是分钟,默认是每小时的0分开始执行。
例如,以下每小时时间表触发器在每小时的第30分钟执行,12:30,13:30,14:30等等。
{
...
"trigger" : {
"schedule" : {
"hourly" : { "minute" : 30 }
}
}
...
}
在小时时刻表中可以设置多个分钟执行,例如:
{
...
"trigger" : {
"schedule" : {
"hourly" : { "minute" : [ 0, 15, 30, 45 ] }
}
}
...
}
l daily天时刻表
天时刻表指定每一天在某一特定时间触发的一个计划。要配置一个一天的时间表,指定一个单一的时间与属性。如果不指定,默认是0点执行。例如,下面的作息时间触发一次每天下午5:00执行。
{
...
"trigger" : {
"schedule" : {
"daily" : { "at" : "17:00" }
}
}
...
}
在天时时刻表中可以设置多个时间点执行,例如下面的设置在每天的 00:00, 12:00和 17:00执行:
{
...
"trigger" : {
"schedule" : {
"daily" : { "at" : [ "midnight", "noon", "17:00" ] }
}
}
...
}
midnight和noon是保留字,表示00:00和12:00。
l weekly周时刻表
周时刻表指定每一周在某一特定时间触发的一个计划。可以指定一周的名称、缩写或数字(星期日是一周的第一天):
sunday, monday, tuesday, wednesday, thursday, friday and saturday
sun, mon, tue, wed, thu, fri and sat
1, 2, 3, 4, 5, 6 and 7
例如下面的设置表示每周五下午5点执行:
{
...
"trigger" : {
"schedule" : {
"weekly" : { "on" : "friday", "at" : "17:00" }
}
}
...
}
每周的时刻表也可以设置多个时间点执行,例如:
{
...
"trigger" : {
"schedule" : {
"weekly" : [
{ "on" : "tuesday", "at" : "noon" },
{ "on" : "friday", "at" : "17:00" }
]
}
}
...
}
或者:
{
...
"trigger" : {
"schedule" : {
"weekly" : {
"on" : [ "tuesday", "friday" ],
"at" : [ "noon", "17:00" ]
}
}
}
...
}
l monthly月时刻表
月时刻表指定每一月在某一特定时间触发的一个计划。
例如下面的设置表示每月10日中午12点执行:
{
...
"trigger" : {
"schedule" : {
"monthly" : { "on" : 10, "at" : "noon" }
}
}
...
}
每月的时刻表也可以设置多个时间点执行,例如:
{
...
"trigger" : {
"schedule" : {
"monthly" : [
{ "on" : 10, "at" : "noon" },
{ "on" : 20, "at" : "17:00" }
]
}
}
...
}
或者:
{
...
"trigger" : {
"schedule" : {
"monthly" : {
"on" : [ 10, 20 ],
"at" : [ "midnight", "noon" ]
}
}
}
...
}
l yearly年时刻表
年时刻表指定每一年在某一特定时间触发的一个计划。可以指定月的名称、缩写或数字:
january, february, march, april, may, june, july, august, september, october, november ,december
jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov ,dec
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
例如下面的设置表示每年1月10日中午12点执行:
{
...
"trigger" : {
"schedule" : {
"yearly" : { "in" : "january", "on" : 10, "at" : "noon" }
}
}
...
}
每年的时刻表也可以设置多个时间点执行,例如:
{
...
"trigger" : {
"schedule" : {
"yearly" : [
{ "in" : "january", "on" : 10, "at" : "noon" },
{ "in" : "july", "on" : 20, "at" : "17:00" }
]
}
}
...
}
或者:
{
...
"trigger" : {
"schedule" : {
"yearly" : {
"in: : [ "jan", "dec" ],
"on" : [ 10, 20 ],
"at" : [ "midnight", "noon" ]
}
}
}
...
}
l cron表达式时刻表
域名称 | 是否必须 | 字段返回 | 特殊字符 |
seconds | yes | 0-59 | , - * / |
minutes | yes | 0-59 | , - * / |
hours | yes | 0-23 | , - * / |
day_of_month | yes | 1-31 | , - * / ? L W |
month | yes | 1-12 or JAN-DEC | , - * / |
day_of_week | yes | 1-7 or SUN-SAT | , - * / ? L # |
year | no | empty or 1970-2099 | , - * / |
表格9.2 cron表达式元素说明
特殊字符,它们的含义是:
*:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
?:只能用在day_of_month和day_of_week两个域。它也匹配域的任意值,但实际不会。因为day_of_month和day_of_week会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
/:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
,:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
L:表示最后,只能出现在day_of_month和day_of_week域,如果在day_of_week域使用5L,意味着在最后的一个星期四触发。
W:表示有效工作日(周一到周五),只能出现在day_of_month域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 day_of_month使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份
LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
#:用于确定每个月第几个星期几,只能出现在day_of_month域。例如在4#2,表示某月的第二个星期三。
例如下面的表达式表示每天中午12点执行:
{
...
"trigger" : {
"schedule" : {
"cron" : "0 0 12 * * ?"
}
}
...
}
l interval系统内置表达式:
系统内置表达式可以设置 seconds, minutes, hours, days, weeks:
"Xs" 表示每多少秒执行一次。例如: "30s"表示每30秒执行一次。
"Xm"表示每多少分钟执行一次。例如: "5m"表示每5分钟执行一次。
"Xh"表示每多少小时执行一次。例如: "12h"表示每12小时执行一次。
"Xd"表示每多少天执行一次。例如: "3d"表示每3天执行一次。
"Xw"表示每多少周执行一次。例如: "2w"表示每2周执行一次。
例如下面的例子表示每5分钟执行一次:
{
...
"trigger" : {
"schedule" : {
"interval" : "5m"
}
}
...
}
Inputs
输入将静态数据加载到告警执行上下文中作为判断的内容,系统支持四种类型输入源: simple, search, http , chain。
l Simple Input简单输入
简单输入是指将静态的内容加载到告警执行的上下文中,可以定义一个字符串(STR)、数值(NUM),或一个对象(目标)等静态数据作为输入源。例如,下面的告警使用了简单的输入来设置一个提醒电子邮件,在中午的每一天执行:
{
"trigger" : {
"schedule" : {
"daily" : { "at" : "noon" }
}
},
"input" : {
"simple" : {
"name" : "John"
}
},
"actions" : {
"reminder_email" : {
"email" : {
"to" : "to@host.domain",
"subject" : "Reminder",
"body" : "Dear {
{ctx.payload.name}}, by the time you read these lines, I'll be gone"}
}
}
}
l Search Input搜索输入
搜索输入只指通过Elasticsearch的搜索的结果作为输入加载到告警执行上下文中作为判断的内容。Conditions, transforms, actions都可以通过结果属性访问搜素中的内容。
例如:
ctx.payload.hits,可以表示搜索的所有内容;
ctx.payload.hits.total,可以表示搜索的结果条数;
ctx.payload.hits.hits.2,可以表示搜索结果的第三条数据。
下面表示搜索所有的日志作为输入的实例:
"input" : {
"search" : {
"request" : {
"indices" : [ "logs" ],
"types" : [ "event" ],
"body" : {
"query" : { "match_all" : {}}
}
}
}
}
下面表示通过模板搜索的日志作为输入的实例:
{
"input" : {
"search" : {
"request" : {
"indices" : [ "logs" ],
"template" : {
"id" : "my_template",
"params" : {
"value" : 23
}
}
}
}
}
...
}
l HTTP Input HTTP协议输入
HTTP协议输入指通过HTTP请求Elasticsearch得到的返回结果作为输入加载到告警执行上下文中作为判断的内容。例如:
"input" : {
"http" : {
"request" : {
"host" : "example.com",
"port" : 9200,
"path" : "/idx/_search"
}
}
}
或者用过DSL语言进行查询:
"input" : {
"http" : {
"request" : {
"host" : "host.domain",
"port" : 9200,
"path" : "/idx/_search",
"body" : "{\"query\" : { \"match\" : { \"category\" : \"event\"}}}"
}
}
}
或者通过模板来进行查询:
"input" : {
"http" : {
"request" : {
"host" : "host.domain",
"port" : 9200,
"path" : "/{
{ctx.watch_id}}/_search","body" : "{\"query\" : {\"range\": {\"@timestamp\" : {\"from\": \"{
{ctx.trigger.triggered_time}}||-5m\",\"to\": \"{ {ctx.trigger.triggered_time}}\"}}}}"}
}
}
也可以通过调用Elasticsearch API来进行查询:
"input" : {
"http" : {
"request" : {
"host" : "host.domain",
"port" : "9200",
"path" : "/_cluster/stats",
"params" : {
"human" : "true"
}
}
}
}
l Chain Input链式输入
链式输入是指可以一次把多个输入加载到告警执行上下文中作为判断的内容。当基于来自多个源的数据执行操作时,链输入是有用的。还可以使一个输入收集的数据是从另一个源加载数据。例如,以下链输入数据使用由一个简单的输入路径来自HTTP服务器的请求:
{
"input" : {
"chain" : {
"inputs" : [
{
"first" : {
"simple" : { "path" : "/_search" }
}
},
{
"second" : {
"http" : {
"request" : {
"host" : "localhost",
"port" : 9200,
"path" : "{
{ctx.payload.first.path}}" ‚}
}
}
}
]
}
}
...
}
在一个链中的输入被指定为一个数组,以保证输入的顺序处理。
‚加载由第一个输入设置的路径。本文由赛克 蓝德(secisland)原创,转载请标明作者和出处。
Conditions
当一个告警被触发时,Conditions配置的条件是否满足决定了是否执行下一步的动作。系统支持四中类型的条件类型always, never, script, compare。
l Always Condition
表示触发时间到后始终要执行。例如:
"condition" : {
"always" : {}
}
l Never Condition
表示永远不会被执行,这种情况通常只用于测试。例如:
PUT _watcher/watch/my-watch
{
...
"condition" : {
"never" : {}
}
...
}
l Script Condition
表示用一个脚本来表示告警的条件。默认脚本语言Groovy。可以使用任何Elasticsearch支持的脚本语言。以下代码片段将使用内联脚本的情况总是返回true:
"condition" : {
"script" : "return true"
}
可以使用文件作为脚本数据源,例如:
"condition" : {
"script" : {
"file" : "my_script",
"lang" : "javascript",
"params" : {
"result" : true
}
}
}
l Compare Condition
表示一种简单的将执行上下文模型中的值与给定值进行比较的告警条件。例如下面的例子表示查询的结果条数大于等于5的时候满足条件:
{
...
"condition" : {
"compare" : {
"ctx.payload.hits.total" : {
"gte" : 5
}
}
...
}
条件有以下几种:eq等于,not_eq不等于,gt大于,gte大于等于,lt小于,lte小于等于。
例如:
{
...
"condition" : {
"compare" : {
"ctx.payload.aggregations.status.buckets.error.doc_count" : {
"not_eq" : "{
{ctx.payload.aggregations.handled.buckets.true.doc_count}}"}
}
...
}
Transforms
转换这项不是必须的,表示在输入到执行动作的过程中进行的数据处理。可以定义在两个地方的变换:
1、在定义告警的顶级结构中,在这种情况下,在执行任何告警操作之前被转换。
2、作为一个特定行动定义的一部分。在这种情况下,执行该操作之前被转换。变换仅适用于特定的动作转换。
例如下面的示例定义了两个转换,一个是全局转换和一个在my_webhook行为中进行转换。
{
"trigger" : { ...}
"input" : { ... },
"condition" : { ... },
"transform" : {
"search" : {
"body" : { "query" : { "match_all" : {} } }
}
}
"actions" : {
"my_webhook": {
"transform" : {
"script" : "return ctx.payload.hits"
}
"webhook" : {
"host" : "host.domain",
"port" : 8089,
"path" : "/notify/{
{ctx.watch_id}}"}
}
]
...
}
转换支持搜索转换,脚本转换和链转换
l Search Transform
在群集上执行搜索的转换,并用返回的搜索结果替换告警执行上下文中的内容,例如:
{
"transform" : {
"search" : {
"request" : {
"indices" : [ "logstash-*" ],
"body" : {
"size" : 0,
"query" : {
"match" : { "priority" : "error"}
}
}
}
}
}
}
l Script Transform
在群集上执行脚本的转换,并用返回的脚本执行结果替换告警执行上下文中的内容,例如:
{
...
"transform" : {
"script" : "return [ time : ctx.trigger.scheduled_time ]"
}
...
}
l Chain Transform
链式转换是指可以一次把多个转换加载到转换中,利用它可以建立更复杂的转换。例如,可以将搜索转换和脚本转换同时满足,如下面的示例:
"transform" : {
"chain" : [
{
"search" : {
"indices" : [ "logstash-*" ],
"body" : {
"size" : 0,
"query" : {
"match" : { "priority" : "error" }
}
}
}
},
{
"script" : "return [ error_count : ctx.payload.hits.total ]"
}
]
}
Actions
Actions表示当告警条件被满足时会发生的动作。告警的动作可以是邮件,HipChat,Slack等,详见9.1.3章节。例如:
PUT _watcher/watch/log_event_watch
{
"metadata" : {
"color" : "red"
},
"trigger" : {
"schedule" : {
"interval" : "5m"
}
},
"input" : {
"search" : {
"request" : {
"indices" : "log-events",
"body" : {
"size" : 0,
"query" : { "match" : { "status" : "error" } }
}
}
}
},
"condition" : {
"script" : "return ctx.payload.hits.total > 5"
},
"actions" : {
"email_administrator" : {
"throttle_period": "15m",
"email" : {
"to" : "sys.admino@host.domain",
"subject" : "Encountered {
{ctx.payload.hits.total}} errors","body" : "Too many error in the system, see attached data",
"attachments" : {
"attached_data" : {
"data" : {
"format" : "json"
}
}
},
"priority" : "high"
}
}
}
}
表示触发动作的周期在15分钟,以减少告警的数量。
赛克蓝德(secisland)后续会逐步对Elasticsearch的最新版本的各项功能进行分析,近请期待。也欢迎加入secisland公众号进行关注。