/[nagios-plugins-perl]/trunk/plugins/check_elastic.pl
ViewVC logotype

Contents of /trunk/plugins/check_elastic.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 204 - (show annotations) (download)
Fri Oct 5 14:59:46 2018 UTC (2 years, 1 month ago) by racvision
File MIME type: text/plain
File size: 8284 byte(s)
Fusion des modifs sur supervision01/02 et racvision3. Pas fini.
1 #!/usr/bin/perl -w
2 #
3 # Copyright (c) 2017 St├ęphane URBANOVSKI - CRT Supervision
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #
19 #
20
21 use strict;
22 use warnings;
23
24 use POSIX qw(strftime setlocale);
25 use File::Basename;
26
27 use Locale::gettext;
28
29 use LWP::UserAgent; # http client
30 use HTTP::Request; # used by LWP::UserAgent
31 use HTTP::Status; # to get http err msg
32
33 use JSON::XS;
34
35 use Nagios::Plugin ;
36
37 use Data::Dumper;
38 $Data::Dumper::Terse = 1;
39
40
41 my $VERSION = '1.1';
42 my $TIMEOUT = 60;
43
44 my $tookWarn = 0.2;
45 my $tookCrit = 1.5;
46
47 my $np = Nagios::Plugin->new(
48 version => $VERSION,
49 blurb => 'Query Elasticsearch and check hits returned',
50 usage => "Usage: %s [ -v|--verbose ] [-t <timeout>] ",
51 timeout => $TIMEOUT+1
52 );
53
54
55 $np->add_arg (
56 spec => 'filter=s@',
57 help => _gt('Terms series (filter) to be searched'),
58 );
59 $np->add_arg (
60 spec => 'should=s@',
61 help => _gt('Terms series (should) to be searched'),
62 );
63 $np->add_arg (
64 spec => 'query=s',
65 help => _gt('ES query to be searched'),
66 );
67 $np->add_arg (
68 spec => 'dontcount',
69 help => _gt('Don\'t try to count all hits, stops after the first hit returned'),
70 );
71
72 $np->add_arg (
73 spec => 'eshost=s',
74 help => _gt('Elasticsearch hostname'),
75 default => 'localhost',
76 );
77 $np->add_arg (
78 spec => 'esport=i',
79 help => _gt('Elasticsearch port'),
80 default => 9200,
81 );
82 $np->add_arg (
83 spec => 'esuser=s',
84 help => _gt('Elasticsearch user login'),
85 default => 'admin',
86 );
87 $np->add_arg (
88 spec => 'espass=s',
89 help => _gt('Elasticsearch password'),
90 );
91
92 $np->add_arg (
93 spec => 'hitw=s',
94 help => _gt('Returned hits warning threshold'),
95 default => '1:',
96 );
97 $np->add_arg (
98 spec => 'hitc=s',
99 help => _gt('Returned hits critical threshold'),
100 default => '',
101 );
102
103 $np->add_arg (
104 spec => 'index=s',
105 help => _gt('ES indexes to use (use strftime pattern substitutions) Exemple: events-*-%Y.%m.%d'),
106 default => '_all',
107 );
108
109 $np->add_arg (
110 spec => 'delta=i',
111 help => _gt('Interval of time to use (s) until now'),
112 default => 15*60,
113 );
114
115
116 $np->add_arg (
117 spec => 'label=s',
118 help => 'Additionnal information added to output',
119 );
120
121
122 $np->getopts;
123
124 my $DEBUG = $np->opts->verbose;
125
126 my $eshost = $np->opts->get('eshost');
127 my $esport = $np->opts->get('esport');
128 my $esuser = $np->opts->get('esuser');
129 my $espass = $np->opts->get('espass');
130
131
132 my $hitw = $np->opts->get('hitw');
133 my $hitc = $np->opts->get('hitc');
134
135 my $esindexPattern = $np->opts->get('index');
136
137 my $label = $np->opts->get('label');
138
139 my $deltaTime = $np->opts->get('delta');
140
141 my $queryFilter = $np->opts->get('filter');
142 my $queryShould = $np->opts->get('should');
143 my $query = $np->opts->get('query');
144 my $terminate_after = $np->opts->get('dontcount') ? 1 : 0;
145
146
147 # Create a LWP user agent object:
148 my $ua = new LWP::UserAgent(
149 'env_proxy' => 0,
150 'timeout' => $TIMEOUT,
151 );
152 $ua->agent(basename($0));
153
154 # Workaround for LWP bug :
155 $ua->parse_head(0);
156
157 my $esindex = '_all';
158
159
160 my $cred = '';
161 if ( defined($espass) ) {
162 $cred = $esuser.':'.$espass.'@';
163 }
164
165 # handle indexes named with time reference
166 if ( defined($esindexPattern) ) {
167 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
168
169 $esindex = POSIX::strftime( $esindexPattern, $sec,$min,$hour,$mday,$mon,$year );
170
171 # Add previous day when using daily patterns
172 # FIXME: this hack works only for daily pattern.
173 if ( $esindexPattern =~ /%d/ ) {
174 $esindex .= ','.POSIX::strftime( $esindexPattern, $sec,$min,$hour,$mday - 1,$mon,$year );
175 }
176
177 logD('Using index pattern : '.$esindex );
178 }
179
180 # TODO: choose protocol
181
182 my $esUrl = 'https://'.$cred.$eshost.':'.$esport.'/'.$esindex.'/_search?ignore_unavailable=true';
183
184 logD2("URL: ".$esUrl );
185
186
187 $np->set_thresholds('warning' => $hitw, 'critical' => $hitc);
188
189 my $tsEnd = time();
190 my $esTime = 0;
191
192
193 my $dateEndUTC = POSIX::strftime("%Y-%m-%dT%T",gmtime($tsEnd));
194 my $timeEnd = strftime("%T",localtime($tsEnd));
195 my $dateStartUTC = POSIX::strftime("%Y-%m-%dT%T",gmtime($tsEnd - $deltaTime));
196 my $timeStart = strftime("%T",localtime($tsEnd - $deltaTime));
197
198
199 logD2('TERMS: $queryFilter='.Dumper(\$queryFilter) );
200
201 my %esQueryFilter = ();
202
203 foreach my $t ( @{$queryFilter} ) {
204 if ( $t =~ /^([\w\.]+)\:(.*)/ ) {
205 my ($k,$v) = ($1,$2);
206 # $v =~ s/([\"\'])/\\$1/g;
207 $esQueryFilter{$k} = $v;
208 } else {
209 logD ("Bad filter term definition : $t");
210 }
211 }
212
213 my %esQueryShould = ();
214
215 foreach my $t ( @{$queryShould} ) {
216 if ( $t =~ /^([\w\.]+)\:(.*)/ ) {
217 my ($k,$v) = ($1,$2);
218 $v =~ s/([\"\'])/\\$1/g;
219 $esQueryShould{$k} = $v;
220 } else {
221 logD ("Bad should term definition : $t");
222 }
223 }
224
225
226
227 my $esQuery = {
228 'query' => {
229 'bool' => {
230 'filter' => [
231 {
232 'range' => {
233 '@timestamp' => {
234 'gte' => $dateStartUTC,
235 'lt' => $dateEndUTC
236 },
237 },
238 },
239 ],
240 },
241 },
242 'size' => 0,
243 'terminate_after' => $terminate_after
244 };
245
246
247 if ( defined($query) ) {
248 push( @{$esQuery->{'query'}{'bool'}{'filter'}}, {
249 'query_string' => {
250 'query' => $query,
251 'analyze_wildcard' => JSON::XS::false,
252 }
253 });
254 }
255 foreach my $k ( keys(%esQueryFilter) ) {
256 push( @{$esQuery->{'query'}{'bool'}{'filter'}}, {
257 'term' => {
258 $k => $esQueryFilter{$k}
259 }
260 });
261 }
262
263
264
265 my $jsonQuery = encode_json($esQuery);
266
267 my $esRequest = HTTP::Request->new('POST', $esUrl);
268 $esRequest->content_type('application/json');
269
270 logD2('POST: '.JSON::XS->new->pretty(1)->encode($esQuery) ) if $DEBUG>1;
271 $esRequest->content($jsonQuery);
272
273 my $timer = time();
274 my $http_response = $ua->request( $esRequest );
275 $timer = time()-$timer;
276
277 $esTime += $timer;
278
279 if ( $http_response->is_error() ) {
280 my $err = $http_response->code." ".status_message($http_response->code)." (".$http_response->message.")";
281 logD("ES Query failed : HTTP error: ".$err );
282 $np->nagios_exit(UNKNOWN, sprintf(_gt('ES Query failed (%s)'),$err ));
283
284 }
285 my $json = $http_response->content;
286
287 logD('RESPONSE: $json='.Dumper(\$json) );
288
289 my $jdata;
290 eval {
291 $jdata = decode_json($json);
292 };
293 if ($@) {
294 logD ('Enable to decode json : '.$json);
295 $np->nagios_exit(UNKNOWN, _gt('Enable to decode json returned') );
296 }
297 # print Dumper(\$jdata)."\n";
298
299 if ( !defined($jdata->{'hits'}{'hits'}) ) {
300 $np->nagios_exit(UNKNOWN, _gt('Invalid ES response returned !') );
301 }
302
303
304 # check search time
305
306 my $took = $jdata->{'took'}/1000; # ms -> s
307
308 my $tookStatus = $np->check_threshold(
309 'check' => $took,
310 'warning' => $tookWarn,
311 'critical' => $tookCrit,
312 );
313 $np->add_perfdata(
314 'label' => 't',
315 'value' => $took,
316 'min' => 0,
317 'uom' => 's',
318 'threshold' => $np->threshold()
319 );
320
321 my $shardsUsed = $jdata->{'_shards'}{'total'} || 0;
322
323 # check failed shards
324 if ( defined($jdata->{'_shards'}{'failed'}) && $jdata->{'_shards'}{'failed'} > 0 ) {
325 $np->add_message(WARNING, sprintf(_gt('Some shards failed (%d/%d)!'), $jdata->{'_shards'}{'failed'}, $shardsUsed) );
326 }
327
328
329 my $hits = $jdata->{'hits'}{'total'};
330
331 my $hitStatus = $np->check_threshold(
332 'check' => $hits,
333 'warning' => $hitw,
334 'critical' => $hitc,
335 );
336 $np->add_perfdata(
337 'label' => 'hits',
338 'value' => $hits,
339 'min' => 0,
340 'threshold' => $np->threshold()
341 );
342
343 if ( $hitStatus ) {
344 $np->add_message($hitStatus, sprintf(_gt('Hit count (%d) out of range !'),$hits) );
345 } else {
346 $np->add_message($hitStatus, sprintf(_gt('%d hits between %s and %s (%d shards used)'),$hits,$timeStart,$timeEnd,$shardsUsed) );
347 }
348
349 my ($status, $message) = $np->check_messages('join' => ' ');
350
351 if ( $label ) {
352 $message = sprintf('%s - %s', $label,$message);
353 }
354
355 $np->nagios_exit($status, $message );
356
357
358
359 # Gettext wrapper
360 sub _gt {
361 return gettext($_[0]);
362 }
363 sub logD {
364 my ($msg) = @_;
365 print STDERR "DEBUG: $msg\n" if $DEBUG;
366 }
367 sub logD2 {
368 my ($msg) = @_;
369 print STDERR "DEBUG2: $msg\n" if $DEBUG>1;
370 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.8