/[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 - (hide annotations) (download)
Fri Oct 5 14:59:46 2018 UTC (2 years, 3 months ago) by racvision
File MIME type: text/plain
File size: 8284 byte(s)
Fusion des modifs sur supervision01/02 et racvision3. Pas fini.
1 racvision 191 #!/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 racvision 204 my $TIMEOUT = 60;
43 racvision 191
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 mcoquard 194 $np->add_arg (
68     spec => 'dontcount',
69     help => _gt('Don\'t try to count all hits, stops after the first hit returned'),
70     );
71 racvision 191
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 mcoquard 194 my $terminate_after = $np->opts->get('dontcount') ? 1 : 0;
145 racvision 191
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 mcoquard 194
169 racvision 191 $esindex = POSIX::strftime( $esindexPattern, $sec,$min,$hour,$mday,$mon,$year );
170 mcoquard 194
171 racvision 191 # Add previous day when using daily patterns
172 mcoquard 194 # FIXME: this hack works only for daily pattern.
173 racvision 191 if ( $esindexPattern =~ /%d/ ) {
174     $esindex .= ','.POSIX::strftime( $esindexPattern, $sec,$min,$hour,$mday - 1,$mon,$year );
175 mcoquard 194 }
176    
177 racvision 191 logD('Using index pattern : '.$esindex );
178     }
179    
180     # TODO: choose protocol
181    
182 racvision 204 my $esUrl = 'https://'.$cred.$eshost.':'.$esport.'/'.$esindex.'/_search?ignore_unavailable=true';
183 racvision 191
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 mcoquard 194
193 racvision 191 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 mcoquard 194
198    
199 racvision 191 logD2('TERMS: $queryFilter='.Dumper(\$queryFilter) );
200 mcoquard 194
201 racvision 191 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 mcoquard 194
213 racvision 191 my %esQueryShould = ();
214 mcoquard 194
215 racvision 191 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 mcoquard 194
225    
226    
227 racvision 191 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 mcoquard 194 'size' => 0,
243     'terminate_after' => $terminate_after
244 racvision 191 };
245    
246 mcoquard 194
247 racvision 191 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 mcoquard 194
265 racvision 191 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 mcoquard 194
284 racvision 191 }
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 mcoquard 194
304 racvision 191 # 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