File Coverage

blib/lib/Nagios/Plugins/Memcached.pm
Criterion Covered Total %
statement 21 106 19.8
branch 0 26 0.0
condition 0 23 0.0
subroutine 7 18 38.8
pod 9 9 100.0
total 37 182 20.3


line stmt bran cond sub pod time code
1             package Nagios::Plugins::Memcached;
2              
3 1     1   7 use strict;
  1         2  
  1         306  
4 1     1   7 use warnings;
  1         2  
  1         44  
5              
6 1     1   5 use base qw(Nagios::Plugin);
  1         2  
  1         1047  
7              
8 1     1   63535 use Carp::Clan;
  1         12732  
  1         8  
9 1     1   1030 use Cache::Memcached;
  1         168433  
  1         36  
10 1     1   45 use Nagios::Plugin;
  1         2  
  1         76  
11 1     1   5 use Time::HiRes qw(time);
  1         2  
  1         8  
12              
13             =head1 NAME
14              
15             Nagios::Plugins::Memcached - Nagios plugin to observe memcached.
16              
17             =head1 VERSION
18              
19             version 0.02
20              
21             =cut
22              
23             our $VERSION = '0.02';
24              
25             =head1 SYNOPSIS
26              
27             use Nagios::Plugins::Memcached;
28              
29             my $np = Nagios::Plugins::Memcached->new;
30             $np->run;
31              
32             =head1 DESCRIPTION
33              
34             Please setup your nagios config.
35              
36             ### check response time(msec) for memcached
37             define command {
38             command_name check_memcached_response
39             command_line /usr/bin/check_memcached -H $HOSTADDRESS$ -w 3 -c 5
40             }
41              
42             ### check cache size ratio(bytes/limit_maxbytes[%]) for memcached
43             define command {
44             command_name check_memcached_size
45             command_line /usr/bin/check_memcached -H $HOSTADDRESS$ --size-warning 60 --size-critical 80
46             }
47              
48             ### check cache hit ratio(get_hits/cmd_get[%]) for memcached
49             define command {
50             command_name check_memcached_hit
51             command_line /usr/bin/check_memcached -H $HOSTADDRESS$ --hit-warning 40 --size-critical 20
52             }
53              
54             This plugin can execute with all threshold options together.
55              
56             =head2 Command Line Options
57              
58             Usage for L command.
59              
60             Usage: check_memcached [-H host] [-w warnings] [-c critical] [--size-warnng size-warnng] [--size-critical size-critical] [--hit-warning hit-warning] [--hit-critical hit-critical] [-t timeout] [-v] [-h] [-?] [-V] [--extra-opts section@config_file]
61            
62             -?, --usage
63             Print usage information
64             -h, --help
65             Print detailed help screen
66             -V, --version
67             Print version information
68             --extra-opts=[
[@]]
69             Section and/or config_file from which to load extra options (may repeat)
70             -H, --hosts=ADDRESS[:PORT] or HOSTNAME[:PORT] or UNIX_SOCKET
71             Available multiple value. default is localhost:11211
72             -w, --warnings=INTEGER
73             Time threshold on warning. This unit of the value is msec.
74             -c, --critical=INTEGER
75             Time threshold on critical. This unit of the value is msec.
76             --size-warning=INTEGER
77             Size threshold on warning. This unit of the value is percent.
78             --size-critical=INTEGER
79             Size threshold on critical. This unit of the value is percent.
80             --hit-warning=INTEGER
81             Hit threshold on warning. This unit of the value is percent.
82             --hit-critical=INTEGER
83             Hit threshold on critical. This unit of the value is percent.
84             -t, --timeout=INTEGER
85             Seconds before plugin times out (default: 15)
86             -v, --verbose
87             Show details for command-line debugging (can repeat up to 3 times)
88              
89             =head1 PROPERTIES
90              
91             =head2 $TIMEOUT(=4)
92              
93             Default value of connection timeout(sec) between the memcached server.
94              
95             =cut
96              
97             our $TIMEOUT = 4;
98              
99             =head1 METHODS
100              
101             =head2 new()
102              
103             create instance.
104              
105             =cut
106              
107             sub new {
108 0     0 1   my $class = shift;
109              
110 0           my %args = (
111             shortname => 'MEMCACHED',
112             usage =>
113             'Usage: %s [-H host] [-w warnings] [-c critical] [--size-warnng size-warnng] [--size-critical size-critical] [--hit-warning hit-warning] [--hit-critical hit-critical] [-t timeout] [-v] [-h] [-?] [-V] [--extra-opts section@config_file]',
114             version => $VERSION,
115             url =>
116             'http://search.cpan.org/dist/Nagios-Plugins-Memcached/bin/check_memcache',
117             license =>
118             qq|This library is free software, you can redistribute it and/or modify\nit under the same terms as Perl itself.|,
119             );
120              
121 0           my $self = $class->SUPER::new(%args);
122              
123 0           $self->setup;
124              
125 0           return $self;
126             }
127              
128             =head2 setup()
129              
130             setup this plugin.
131              
132             =cut
133              
134             sub setup {
135 0     0 1   my ($self) = @_;
136              
137 0           $self->setup_args;
138             }
139              
140             =head2 setup_args()
141              
142             setup arguments.
143              
144             =cut
145              
146             sub setup_args {
147 0     0 1   my ($self) = @_;
148              
149 0           my @args = (
150             { spec => 'hosts|H=s@',
151             help =>
152             qq|-H, --hosts=ADDRESS[:PORT] or HOSTNAME[:PORT] or UNIX_SOCKET\n Available multiple value. default is localhost:11211|
153             },
154             { spec => 'warning|w=s',
155             help =>
156             qq|-w, --warnings=INTEGER\n Time threshold on warning. This unit of the value is msec.|
157             },
158             { spec => 'critical|c=s',
159             help =>
160             qq|-c, --critical=INTEGER\n Time threshold on critical. This unit of the value is msec.|
161             },
162             { spec => 'size-warning=s',
163             help =>
164             qq|--size-warning=INTEGER\n Size threshold on warning. This unit of the value is percent.|
165             },
166             { spec => 'size-critical=s',
167             help =>
168             qq|--size-critical=INTEGER\n Size threshold on critical. This unit of the value is percent.|
169             },
170             { spec => 'hit-warning=s',
171             help =>
172             qq|--hit-warning=INTEGER\n Hit threshold on warning. This unit of the value is percent.|
173             },
174             { spec => 'hit-critical=s',
175             help =>
176             qq|--hit-critical=INTEGER\n Hit threshold on critical. This unit of the value is percent.|
177             },
178             );
179              
180 0           $self->add_arg(%$_) for (@args);
181             }
182              
183             =head2 run()
184              
185             run checks.
186              
187             =cut
188              
189             sub run {
190 0     0 1   my ($self) = @_;
191              
192 0           $self->getopts;
193              
194 0           my $hosts = $self->opts->get("hosts");
195              
196 0 0         unless ($hosts) {
197 0   0       $hosts ||= ["localhost:11211"];
198             }
199              
200 0           $hosts = [map { $self->normalize_host($_) } @$hosts];
  0            
201 0           $self->opts->set("hosts", $hosts);
202              
203 0           my @runmodes = $self->detect_runmodes;
204              
205             # if (@runmodes == 0) {
206             # $self->nagios_exit(UNKNOWN, 'Not running any check.');
207             # return;
208             # }
209              
210 0           $self->add_message( OK, "OK" );
211              
212 0           eval {
213 0   0       my $timeout = $self->opts->get("timeout") || $TIMEOUT;
214              
215             local $SIG{ALRM} = sub {
216 0     0     $self->add_message( CRITICAL, "Timeout $timeout sec." );
217 0           croak("Timeout $timeout sec");
218 0           };
219              
220 0           alarm $timeout;
221              
222 0           my $cache = Cache::Memcached->new( { servers => $hosts } );
223              
224             $cache->set_cb_connect_fail(
225             sub {
226 0     0     my $prefip = shift;
227 0           $self->add_message( CRITICAL, "Can't connect to $prefip" );
228 0           croak("Can't connect to $prefip");
229             }
230 0           );
231              
232 0           my $start = time();
233 0           my $stats = $cache->stats( [qw/misc/] );
234 0           my $end = time();
235              
236 0           $stats->{time} = $end - $start;
237              
238 0           for my $runmode (@runmodes) {
239 0           my $method = $runmode->{name};
240 0           $self->$method( $cache, $stats, $runmode->{args} );
241             }
242              
243 0           alarm 0;
244             };
245 0 0 0       if ( $@ && $@ !~ /(Timeout \d+ sec|Can't connect to)/ ) {
246 0           $self->add_message( CRITICAL, join( " ", split( "\n", $@ ) ) );
247             }
248              
249 0           $self->nagios_exit( $self->check_messages( join => ", " ) );
250 0           return;
251             }
252              
253             =head2 check_time($cache, $stats, $args)
254              
255             check execute times of stats.
256              
257             =cut
258              
259             sub check_time {
260 0     0 1   my ( $self, $cache, $stats, $args ) = @_;
261              
262 0           $self->add_message( OK, "Time checked: OK" );
263              
264 0           my $code = $self->check_threshold(
265             check => $stats->{time} * 1000,
266             warning => $args->{warning},
267             critical => $args->{critical}
268             );
269              
270 0 0         $self->add_message( $code, "Time checked: NG" ) if ( $code > OK );
271              
272 0           $self->add_perfdata(
273             label => 'time',
274             value => sprintf( "%.4f", $stats->{time} * 1000 ),
275             uom => '[msec]',
276             threshold => $self->threshold
277             );
278             }
279              
280             =head2 check_size($cache, $stats, $args)
281              
282             check using bytes ratio.
283              
284             =cut
285              
286             sub check_size {
287 0     0 1   my ( $self, $cache, $stats, $args ) = @_;
288              
289 0           for my $host ( keys %{ $stats->{hosts} } ) {
  0            
290 0           my $host_stats = $stats->{hosts}->{$host}->{misc};
291              
292 0           $self->add_message( OK, "Size checked; OK - at $host" );
293              
294 0           my $use_size
295             = $host_stats->{bytes} * 100 / $host_stats->{limit_maxbytes};
296              
297 0           my $code = $self->check_threshold(
298             check => $use_size,
299             warning => $args->{warning},
300             critical => $args->{critical}
301             );
302              
303 0 0         $self->add_message( $code, "Size checked: NG - at $host" )
304             if ( $code > OK );
305              
306 0           $self->add_perfdata(
307             label => 'size',
308             value => sprintf( "%.2f", $use_size ),
309             uom => '[%]',
310             threshold => $self->threshold
311             );
312             }
313             }
314              
315             =head2 check_hit($cache, $stats, $args)
316              
317             check cache hit ratio.
318              
319             =cut
320              
321             sub check_hit {
322 0     0 1   my ( $self, $cache, $stats, $args ) = @_;
323              
324 0           for my $host ( keys %{ $stats->{hosts} } ) {
  0            
325 0           my $host_stats = $stats->{hosts}->{$host}->{misc};
326              
327 0 0         if ( $host_stats->{cmd_get} == 0 ) {
328 0           $self->add_message( OK,
329             "Hit checked: OK - stats cmd_get is zero at $host" );
330 0           next;
331             }
332              
333 0           $self->add_message( OK, "Hit checked: OK - at $host" );
334              
335 0           my $hits = $host_stats->{get_hits} * 100 / $host_stats->{cmd_get};
336              
337 0           my $code = $self->check_threshold(
338             check => $hits,
339             warning =>
340             sprintf( '@%d:%d', $args->{critical}, $args->{warning} ),
341             critical => sprintf( '@0:%d', $args->{critical} )
342             );
343              
344 0 0         $self->add_message( $code, "Hit checked: NG - at $host" )
345             if ( $code > OK );
346              
347 0           $self->add_perfdata(
348             label => 'hits',
349             value => sprintf( "%.2f", $hits ),
350             uom => '[%]',
351             threshold => $self->threshold
352             );
353             }
354             }
355              
356             =head2 detect_runmodes
357              
358             Detecting runmode.
359              
360             =cut
361              
362             sub detect_runmodes {
363 0     0 1   my ($self) = @_;
364              
365 0           my @runmodes = ();
366 0           my $opts = $self->opts;
367              
368 0 0 0       if ( $opts->get("warning") && $opts->get("critical") ) {
369 0 0         $self->nagios_exit( UNKNOWN,
370             "Invalid arguments - warning > critical" )
371             if ( $opts->get("warning") > $opts->get("critical") );
372              
373 0           push(
374             @runmodes,
375             { name => 'check_time',
376             args => {
377             warning => $opts->get("warning"),
378             critical => $opts->get("critical"),
379             key => $opts->get("key")
380             }
381             }
382             );
383             }
384              
385 0 0 0       if ( $opts->get("hosts")
  0   0        
      0        
386             && @{ $opts->get("hosts") } == 1
387             && $opts->get("size-warning")
388             && $opts->get("size-critical") )
389             {
390 0 0         $self->nagios_exit( UNKNOWN,
391             "Invalid arguments - size-warning > size-critical" )
392             if ( $opts->get("size-warning") > $opts->get("size-critical") );
393              
394 0           push(
395             @runmodes,
396             { name => "check_size",
397             args => {
398             warning => $opts->get("size-warning"),
399             critical => $opts->get("size-critical"),
400             host => $opts->get("hosts")->[0]
401             }
402             }
403             );
404             }
405              
406 0 0 0       if ( $opts->get("hit-warning") && $opts->get("hit-critical") ) {
407 0 0         $self->nagios_exit( UNKNOWN,
408             "Invalid arguments - hit-warning < hit-critical" )
409             if ( $opts->get("hit-warning") < $opts->get("hit-critical") );
410              
411 0           push(
412             @runmodes,
413             { name => "check_hit",
414             args => {
415             warning => $opts->get("hit-warning"),
416             critical => $opts->get("hit-critical"),
417             }
418             }
419             );
420             }
421              
422 0           return @runmodes;
423             }
424              
425             =head2 normalize_host
426              
427             Add default port(11211) if not exists specified port.
428              
429             =cut
430              
431             sub normalize_host {
432 0     0 1   my ($proto, $host) = @_;
433 0 0         return ($host =~ /:\d+$/) ? $host : "$host:11211";
434             }
435              
436             =head1 AUTHOR
437              
438             Toru Yamaguchi, C<< >>
439              
440             =head1 BUGS
441              
442             Please report any bugs or feature requests to
443             C, or through the web interface at
444             L. I will be notified, and then you'll automatically be
445             notified of progress on your bug as I make changes.
446              
447             =head1 COPYRIGHT & LICENSE
448              
449             Copyright 2007 Toru Yamaguchi, All Rights Reserved.
450              
451             This program is free software; you can redistribute it and/or modify it
452             under the same terms as Perl itself.
453              
454             =cut
455              
456             1; # End of Nagios::Plugins::Memcached
457              
458             __END__