sensu-plugins-elasticsearch-boutetnico 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,287 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-es-query
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks an ElasticSearch query.
7
+ #
8
+ # OUTPUT:
9
+ # plain text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: sensu-plugin
16
+ # gem: elasticsearch
17
+ # gem: aws_es_transport
18
+ #
19
+ # USAGE:
20
+ # This example checks that the average of the field "serve_time" in logs matching a query of
21
+ # anything (*) at the host elasticsearch.service.consul for the past 90 minutes
22
+ # will warn if above 120ms and go critical if the result average is above 250ms
23
+ # check-es-query-average.rb -h elasticsearch.service.consul -q "*"
24
+ # --types special_type -d 'logging-%Y.%m.%d' --minutes-previous 90 -p 9200 -c 0.250 -w 0.120 -a serve_time
25
+ #
26
+ # NOTES:
27
+ #
28
+ # LICENSE:
29
+ # Itamar Lavender <itamar.lavender@gmail.com>
30
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
31
+ # for details.
32
+ #
33
+
34
+ require 'sensu-plugin/check/cli'
35
+ require 'elasticsearch'
36
+ require 'time'
37
+ require 'uri'
38
+ require 'aws_es_transport'
39
+ require 'sensu-plugins-elasticsearch'
40
+
41
+ #
42
+ # ES Query Count
43
+ #
44
+ class ESQueryAverage < Sensu::Plugin::Check::CLI
45
+ include ElasticsearchCommon
46
+
47
+ option :index,
48
+ description: 'Elasticsearch indices to query.
49
+ Comma-separated list of index names to search.
50
+ Use `_all` or empty string to perform the operation on all indices.
51
+ Accepts wildcards',
52
+ short: '-i INDEX',
53
+ long: '--indices INDEX'
54
+
55
+ option :transport,
56
+ long: '--transport TRANSPORT',
57
+ description: 'Transport to use to communicate with ES. Use "AWS" for signed AWS transports.'
58
+
59
+ option :region,
60
+ long: '--region REGION',
61
+ description: 'Region (necessary for AWS Transport)'
62
+
63
+ option :types,
64
+ description: 'Elasticsearch types to limit searches to, comma separated list.',
65
+ long: '--types TYPES'
66
+
67
+ option :timestamp_field,
68
+ description: 'Field to use instead of @timestamp for query.',
69
+ long: '--timestamp-field FIELD_NAME',
70
+ default: '@timestamp'
71
+
72
+ option :offset,
73
+ description: 'Seconds before offset to end @timestamp against query.',
74
+ long: '--offset OFFSET',
75
+ proc: proc(&:to_i),
76
+ default: 0
77
+
78
+ option :ignore_unavailable,
79
+ description: 'Ignore unavailable indices.',
80
+ long: '--ignore-unavailable',
81
+ boolean: true,
82
+ default: true
83
+
84
+ option :minutes_previous,
85
+ description: 'Minutes before offset to check @timestamp against query.',
86
+ long: '--minutes-previous MINUTES_PREVIOUS',
87
+ proc: proc(&:to_i),
88
+ default: 0
89
+
90
+ option :hours_previous,
91
+ description: 'Hours before offset to check @timestamp against query.',
92
+ long: '--hours-previous HOURS_PREVIOUS',
93
+ proc: proc(&:to_i),
94
+ default: 0
95
+
96
+ option :days_previous,
97
+ description: 'Days before offset to check @timestamp against query.',
98
+ long: '--days-previous DAYS_PREVIOUS',
99
+ proc: proc(&:to_i),
100
+ default: 0
101
+
102
+ option :weeks_previous,
103
+ description: 'Weeks before offset to check @timestamp against query.',
104
+ long: '--weeks-previous WEEKS_PREVIOUS',
105
+ proc: proc(&:to_i),
106
+ default: 0
107
+
108
+ option :months_previous,
109
+ description: 'Months before offset to check @timestamp against query.',
110
+ long: '--months-previous MONTHS_PREVIOUS',
111
+ proc: proc(&:to_i),
112
+ default: 0
113
+
114
+ option :date_index,
115
+ description: 'Elasticsearch time based index.
116
+ Accepts format from http://ruby-doc.org/core-2.2.0/Time.html#method-i-strftime',
117
+ short: '-d DATE_INDEX',
118
+ long: '--date-index DATE_INDEX'
119
+
120
+ option :date_repeat_daily,
121
+ description: 'Elasticsearch date based index repeats daily.',
122
+ long: '--repeat-daily',
123
+ boolean: true,
124
+ default: true
125
+
126
+ option :date_repeat_hourly,
127
+ description: 'Elasticsearch date based index repeats hourly.',
128
+ long: '--repeat-hourly',
129
+ boolean: true,
130
+ default: false
131
+
132
+ option :search_field,
133
+ description: 'The Elasticsearch document field to search for your query string.',
134
+ short: '-f FIELD',
135
+ long: '--field FIELD',
136
+ required: false,
137
+ default: 'message'
138
+
139
+ option :query,
140
+ description: 'Elasticsearch query',
141
+ short: '-q QUERY',
142
+ long: '--query QUERY',
143
+ required: false
144
+
145
+ option :aggr,
146
+ description: 'Elasticsearch query aggr',
147
+ long: '--aggr',
148
+ boolean: true,
149
+ required: false,
150
+ default: true
151
+
152
+ option :aggr_field,
153
+ description: 'Elasticsearch query field to aggregate and average from',
154
+ short: '-a FIELD',
155
+ long: '--aggr-field FIELD',
156
+ required: true
157
+
158
+ option :host,
159
+ description: 'Elasticsearch host',
160
+ short: '-h HOST',
161
+ long: '--host HOST',
162
+ default: 'localhost'
163
+
164
+ option :port,
165
+ description: 'Elasticsearch port',
166
+ short: '-p PORT',
167
+ long: '--port PORT',
168
+ proc: proc(&:to_i),
169
+ default: 9200
170
+
171
+ option :scheme,
172
+ description: 'Elasticsearch connection scheme, defaults to https for authenticated connections',
173
+ short: '-s SCHEME',
174
+ long: '--scheme SCHEME'
175
+
176
+ option :password,
177
+ description: 'Elasticsearch connection password',
178
+ short: '-P PASSWORD',
179
+ long: '--password PASSWORD'
180
+
181
+ option :user,
182
+ description: 'Elasticsearch connection user',
183
+ short: '-u USER',
184
+ long: '--user USER'
185
+
186
+ option :headers,
187
+ description: 'A comma separated list of headers to pass to elasticsearch http client',
188
+ short: '-H headers',
189
+ long: '--headers headers',
190
+ default: 'Content-Type: application/json'
191
+
192
+ option :timeout,
193
+ description: 'Elasticsearch query timeout in seconds',
194
+ short: '-t TIMEOUT',
195
+ long: '--timeout TIMEOUT',
196
+ proc: proc(&:to_i),
197
+ default: 30
198
+
199
+ option :warn,
200
+ short: '-w N',
201
+ long: '--warn N',
202
+ description: 'Result average WARNING threshold',
203
+ proc: proc(&:to_f),
204
+ default: 0
205
+
206
+ option :crit,
207
+ short: '-c N',
208
+ long: '--crit N',
209
+ description: 'Result average CRITICAL threshold',
210
+ proc: proc(&:to_f),
211
+ default: 0
212
+
213
+ option :invert,
214
+ long: '--invert',
215
+ description: 'Invert thresholds',
216
+ boolean: true
217
+
218
+ option :kibana_url,
219
+ long: '--kibana-url KIBANA_URL',
220
+ description: 'Kibana URL query prefix that will be in critical / warning response output.'
221
+
222
+ def kibana_info
223
+ kibana_date_format = '%Y-%m-%dT%H:%M:%S.%LZ'
224
+ unless config[:kibana_url].nil?
225
+ index = config[:index]
226
+ unless config[:date_index].nil?
227
+ date_index_partition = config[:date_index].split('%')
228
+ index = "[#{date_index_partition.first}]" \
229
+ "#{date_index_partition[1..-1].join.sub('Y', 'YYYY').sub('y', 'YY').sub('m', 'MM').sub('d', 'DD').sub('j', 'DDDD').sub('H', 'hh')}"
230
+ end
231
+ end_time = Time.now.utc.to_i
232
+ start_time = end_time
233
+ if config[:minutes_previous] != 0
234
+ start_time -= (config[:minutes_previous] * 60)
235
+ end
236
+ if config[:hours_previous] != 0
237
+ start_time -= (config[:hours_previous] * 60 * 60)
238
+ end
239
+ if config[:days_previous] != 0
240
+ start_time -= (config[:days_previous] * 60 * 60 * 24)
241
+ end
242
+ if config[:weeks_previous] != 0
243
+ start_time -= (config[:weeks_previous] * 60 * 60 * 24 * 7)
244
+ end
245
+ if config[:months_previous] != 0
246
+ start_time -= (config[:months_previous] * 60 * 60 * 24 * 31)
247
+ end
248
+ "Kibana logs: #{config[:kibana_url]}/#/discover?_g=" \
249
+ "(refreshInterval:(display:Off,section:0,value:0),time:(from:'" \
250
+ "#{URI.escape(Time.at(start_time).utc.strftime kibana_date_format)}',mode:absolute,to:'" \
251
+ "#{URI.escape(Time.at(end_time).utc.strftime kibana_date_format)}'))&_a=(columns:!(_source),index:" \
252
+ "#{URI.escape(index)},interval:auto,query:(query_string:(analyze_wildcard:!t,query:'" \
253
+ "#{URI.escape(config[:query])}')),sort:!('@timestamp',desc))&dummy"
254
+ end
255
+ end
256
+
257
+ def run
258
+ response = client.search(build_request_options)
259
+ if config[:invert]
260
+ if response['aggregations']['average']['value'] < config[:crit]
261
+ critical "Query average (#{response['aggregations']['average']['value']}) was below critical threshold. #{kibana_info}"
262
+ elsif response['aggregations']['average']['value'] < config[:warn]
263
+ warning "Query average (#{response['aggregations']['average']['value']}) was below warning threshold. #{kibana_info}"
264
+ else
265
+ ok "Query average (#{response['aggregations']['average']['value']}) was ok"
266
+ end
267
+ elsif response['aggregations']['average']['value'] > config[:crit]
268
+ critical "Query average (#{response['aggregations']['average']['value']}) was above critical threshold. #{kibana_info}"
269
+ elsif response['aggregations']['average']['value'] > config[:warn]
270
+ warning "Query average (#{response['aggregations']['average']['value']}) was above warning threshold. #{kibana_info}"
271
+ else
272
+ ok "Query average (#{response['aggregations']['average']['value']}) was ok"
273
+ end
274
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
275
+ if config[:invert]
276
+ if response['aggregations']['average']['value'] < config[:crit]
277
+ critical "Query average (#{response['aggregations']['average']['value']}) was below critical threshold. #{kibana_info}"
278
+ elsif response['aggregations']['average']['value'] < config[:warn]
279
+ warning "Query average (#{response['aggregations']['average']['value']}) was below warning threshold. #{kibana_info}"
280
+ else
281
+ ok "Query average (#{response['aggregations']['average']['value']}) was ok"
282
+ end
283
+ else
284
+ ok 'No results found, average was below thresholds'
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,275 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-es-query
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks an ElasticSearch query.
7
+ #
8
+ # OUTPUT:
9
+ # plain text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: sensu-plugin
16
+ # gem: elasticsearch
17
+ # gem: aws_es_transport
18
+ #
19
+ # USAGE:
20
+ # This example checks that the count of special_type logs matching a query of
21
+ # anything (*) at the host elasticsearch.service.consul for the past 90 minutes
22
+ # will warn if there are under 100 and go critical if the result count is below 1
23
+ # (The invert flag warns if counts are _below_ the critical and warning values)
24
+ # check-es-query-count.rb -h elasticsearch.service.consul -q "*" --invert
25
+ # --types special_type -d 'logging-%Y.%m.%d' --minutes-previous 90 -p 9200 -c 1 -w 100
26
+ #
27
+ # NOTES:
28
+ #
29
+ # LICENSE:
30
+ # Brendan Gibat <brendan.gibat@gmail.com>
31
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
32
+ # for details.
33
+ #
34
+
35
+ require 'sensu-plugin/check/cli'
36
+ require 'elasticsearch'
37
+ require 'time'
38
+ require 'uri'
39
+ require 'aws_es_transport'
40
+ require 'sensu-plugins-elasticsearch'
41
+
42
+ #
43
+ # ES Query Count
44
+ #
45
+ class ESQueryCount < Sensu::Plugin::Check::CLI
46
+ include ElasticsearchCommon
47
+
48
+ option :index,
49
+ description: 'Elasticsearch indices to query.
50
+ Comma-separated list of index names to search.
51
+ Use `_all` or empty string to perform the operation on all indices.
52
+ Accepts wildcards',
53
+ short: '-i INDEX',
54
+ long: '--indices INDEX'
55
+
56
+ option :transport,
57
+ long: '--transport TRANSPORT',
58
+ description: 'Transport to use to communicate with ES. Use "AWS" for signed AWS transports.'
59
+
60
+ option :region,
61
+ long: '--region REGION',
62
+ description: 'Region (necessary for AWS Transport)'
63
+
64
+ option :types,
65
+ description: 'Elasticsearch types to limit searches to, comma separated list.',
66
+ long: '--types TYPES'
67
+
68
+ option :timestamp_field,
69
+ description: 'Field to use instead of @timestamp for query.',
70
+ long: '--timestamp-field FIELD_NAME',
71
+ default: '@timestamp'
72
+
73
+ option :offset,
74
+ description: 'Seconds before offset to end @timestamp against query.',
75
+ long: '--offset OFFSET',
76
+ proc: proc(&:to_i),
77
+ default: 0
78
+
79
+ option :ignore_unavailable,
80
+ description: 'Ignore unavailable indices.',
81
+ long: '--ignore-unavailable',
82
+ boolean: true,
83
+ default: true
84
+
85
+ option :minutes_previous,
86
+ description: 'Minutes before offset to check @timestamp against query.',
87
+ long: '--minutes-previous MINUTES_PREVIOUS',
88
+ proc: proc(&:to_i),
89
+ default: 0
90
+
91
+ option :hours_previous,
92
+ description: 'Hours before offset to check @timestamp against query.',
93
+ long: '--hours-previous HOURS_PREVIOUS',
94
+ proc: proc(&:to_i),
95
+ default: 0
96
+
97
+ option :days_previous,
98
+ description: 'Days before offset to check @timestamp against query.',
99
+ long: '--days-previous DAYS_PREVIOUS',
100
+ proc: proc(&:to_i),
101
+ default: 0
102
+
103
+ option :weeks_previous,
104
+ description: 'Weeks before offset to check @timestamp against query.',
105
+ long: '--weeks-previous WEEKS_PREVIOUS',
106
+ proc: proc(&:to_i),
107
+ default: 0
108
+
109
+ option :months_previous,
110
+ description: 'Months before offset to check @timestamp against query.',
111
+ long: '--months-previous MONTHS_PREVIOUS',
112
+ proc: proc(&:to_i),
113
+ default: 0
114
+
115
+ option :date_index,
116
+ description: 'Elasticsearch time based index.
117
+ Accepts format from http://ruby-doc.org/core-2.2.0/Time.html#method-i-strftime',
118
+ short: '-d DATE_INDEX',
119
+ long: '--date-index DATE_INDEX'
120
+
121
+ option :date_repeat_daily,
122
+ description: 'Elasticsearch date based index repeats daily.',
123
+ long: '--repeat-daily',
124
+ boolean: true,
125
+ default: true
126
+
127
+ option :date_repeat_hourly,
128
+ description: 'Elasticsearch date based index repeats hourly.',
129
+ long: '--repeat-hourly',
130
+ boolean: true,
131
+ default: false
132
+
133
+ option :search_field,
134
+ description: 'The Elasticsearch document field to search for your query string.',
135
+ short: '-f FIELD',
136
+ long: '--field FIELD',
137
+ required: false,
138
+ default: 'message'
139
+
140
+ option :query,
141
+ description: 'Elasticsearch query',
142
+ short: '-q QUERY',
143
+ long: '--query QUERY',
144
+ required: true
145
+
146
+ option :host,
147
+ description: 'Elasticsearch host',
148
+ short: '-h HOST',
149
+ long: '--host HOST',
150
+ default: 'localhost'
151
+
152
+ option :port,
153
+ description: 'Elasticsearch port',
154
+ short: '-p PORT',
155
+ long: '--port PORT',
156
+ proc: proc(&:to_i),
157
+ default: 9200
158
+
159
+ option :scheme,
160
+ description: 'Elasticsearch connection scheme, defaults to https for authenticated connections',
161
+ short: '-s SCHEME',
162
+ long: '--scheme SCHEME'
163
+
164
+ option :password,
165
+ description: 'Elasticsearch connection password',
166
+ short: '-P PASSWORD',
167
+ long: '--password PASSWORD'
168
+
169
+ option :user,
170
+ description: 'Elasticsearch connection user',
171
+ short: '-u USER',
172
+ long: '--user USER'
173
+
174
+ option :headers,
175
+ description: 'A comma separated list of headers to pass to elasticsearch http client',
176
+ short: '-H headers',
177
+ long: '--headers headers',
178
+ default: 'Content-Type: application/json'
179
+
180
+ option :timeout,
181
+ description: 'Elasticsearch query timeout in seconds',
182
+ short: '-t TIMEOUT',
183
+ long: '--timeout TIMEOUT',
184
+ proc: proc(&:to_i),
185
+ default: 30
186
+
187
+ option :warn,
188
+ short: '-w N',
189
+ long: '--warn N',
190
+ description: 'Result count WARNING threshold',
191
+ proc: proc(&:to_i),
192
+ default: 0
193
+
194
+ option :crit,
195
+ short: '-c N',
196
+ long: '--crit N',
197
+ description: 'Result count CRITICAL threshold',
198
+ proc: proc(&:to_i),
199
+ default: 0
200
+
201
+ option :invert,
202
+ long: '--invert',
203
+ description: 'Invert thresholds',
204
+ boolean: true
205
+
206
+ option :kibana_url,
207
+ long: '--kibana-url KIBANA_URL',
208
+ description: 'Kibana URL query prefix that will be in critical / warning response output.'
209
+
210
+ def kibana_info
211
+ kibana_date_format = '%Y-%m-%dT%H:%M:%S.%LZ'
212
+ unless config[:kibana_url].nil?
213
+ index = config[:index]
214
+ unless config[:date_index].nil?
215
+ date_index_partition = config[:date_index].split('%')
216
+ index = "[#{date_index_partition.first}]" \
217
+ "#{date_index_partition[1..-1].join.sub('Y', 'YYYY').sub('y', 'YY').sub('m', 'MM').sub('d', 'DD').sub('j', 'DDDD').sub('H', 'hh')}"
218
+ end
219
+ end_time = Time.now.utc.to_i
220
+ start_time = end_time
221
+ if config[:minutes_previous] != 0
222
+ start_time -= (config[:minutes_previous] * 60)
223
+ end
224
+ if config[:hours_previous] != 0
225
+ start_time -= (config[:hours_previous] * 60 * 60)
226
+ end
227
+ if config[:days_previous] != 0
228
+ start_time -= (config[:days_previous] * 60 * 60 * 24)
229
+ end
230
+ if config[:weeks_previous] != 0
231
+ start_time -= (config[:weeks_previous] * 60 * 60 * 24 * 7)
232
+ end
233
+ if config[:months_previous] != 0
234
+ start_time -= (config[:months_previous] * 60 * 60 * 24 * 31)
235
+ end
236
+ "Kibana logs: #{config[:kibana_url]}/#/discover?_g=" \
237
+ "(refreshInterval:(display:Off,section:0,value:0),time:(from:'" \
238
+ "#{URI.escape(Time.at(start_time).utc.strftime kibana_date_format)}',mode:absolute,to:'" \
239
+ "#{URI.escape(Time.at(end_time).utc.strftime kibana_date_format)}'))&_a=(columns:!(_source),index:" \
240
+ "#{URI.escape(index)},interval:auto,query:(query_string:(analyze_wildcard:!t,query:'" \
241
+ "#{URI.escape(config[:query])}')),sort:!('@timestamp',desc))&dummy"
242
+ end
243
+ end
244
+
245
+ def run
246
+ response = client.count(build_request_options)
247
+ if config[:invert]
248
+ if response['count'] < config[:crit]
249
+ critical "Query count (#{response['count']}) was below critical threshold. #{kibana_info}"
250
+ elsif response['count'] < config[:warn]
251
+ warning "Query count (#{response['count']}) was below warning threshold. #{kibana_info}"
252
+ else
253
+ ok "Query count (#{response['count']}) was ok"
254
+ end
255
+ elsif response['count'] > config[:crit]
256
+ critical "Query count (#{response['count']}) was above critical threshold. #{kibana_info}"
257
+ elsif response['count'] > config[:warn]
258
+ warning "Query count (#{response['count']}) was above warning threshold. #{kibana_info}"
259
+ else
260
+ ok "Query count (#{response['count']}) was ok"
261
+ end
262
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
263
+ if config[:invert]
264
+ if response['count'] < config[:crit]
265
+ critical "Query count (#{response['count']}) was below critical threshold. #{kibana_info}"
266
+ elsif response['count'] < config[:warn]
267
+ warning "Query count (#{response['count']}) was below warning threshold. #{kibana_info}"
268
+ else
269
+ ok "Query count (#{response['count']}) was ok"
270
+ end
271
+ else
272
+ ok 'No results found, count was below thresholds'
273
+ end
274
+ end
275
+ end