release 0.40
[monitoring-plugin-perl.git] / lib / Monitoring / Plugin / Functions.pm
blob3eaf9e3cbdcbb696200987599c8f685d434ab139
1 package Monitoring::Plugin::Functions;
3 # Functional interface to basic Monitoring::Plugin constants, exports,
4 # and functions
6 use 5.006;
7 use strict;
8 use warnings;
10 use File::Basename;
11 use Params::Validate qw(:types validate);
12 use Math::Calc::Units;
14 # Remember to update Monitoring::Plugins as well
15 our $VERSION = "0.40";
17 our @STATUS_CODES = qw(OK WARNING CRITICAL UNKNOWN DEPENDENT);
19 require Exporter;
20 our @ISA = qw(Exporter);
21 our @EXPORT = (@STATUS_CODES, qw(plugin_exit plugin_die check_messages));
22 our @EXPORT_OK = qw(%ERRORS %STATUS_TEXT @STATUS_CODES get_shortname max_state max_state_alt convert $value_re);
23 our %EXPORT_TAGS = (
24 all => [ @EXPORT, @EXPORT_OK ],
25 codes => [ @STATUS_CODES ],
26 functions => [ qw(plugin_exit plugin_die check_messages max_state max_state_alt convert) ],
29 use constant OK => 0;
30 use constant WARNING => 1;
31 use constant CRITICAL => 2;
32 use constant UNKNOWN => 3;
33 use constant DEPENDENT => 4;
35 our %ERRORS = (
36 'OK' => OK,
37 'WARNING' => WARNING,
38 'CRITICAL' => CRITICAL,
39 'UNKNOWN' => UNKNOWN,
40 'DEPENDENT' => DEPENDENT,
43 our %STATUS_TEXT = reverse %ERRORS;
45 my $value = qr/[-+]?[\d\.]+/;
46 our $value_re = qr/$value(?:e$value)?/;
48 # _fake_exit flag and accessor/mutator, for testing
49 my $_fake_exit = 0;
50 sub _fake_exit { @_ ? $_fake_exit = shift : $_fake_exit };
52 # _use_die flag and accessor/mutator, so exceptions can be raised correctly
53 my $_use_die = 0;
54 sub _use_die { @_ ? $_use_die = shift : $_use_die };
56 sub get_shortname {
57 my $arg = shift;
59 my $shortname = undef;
61 return $arg->{shortname} if (defined($arg->{shortname}));
62 $shortname = $arg->{plugin} if (defined( $arg->{plugin}));
64 $shortname = uc basename($shortname || $ENV{PLUGIN_NAME} || $ENV{NAGIOS_PLUGIN} || $0);
65 $shortname =~ s/^CHECK_(?:BY_)?//; # Remove any leading CHECK_[BY_]
66 $shortname =~ s/\..*$//; # Remove any trailing suffix
67 return $shortname;
70 sub max_state {
71 return CRITICAL if grep { $_ == CRITICAL } @_;
72 return WARNING if grep { $_ == WARNING } @_;
73 return OK if grep { $_ == OK } @_;
74 return UNKNOWN if grep { $_ == UNKNOWN } @_;
75 return DEPENDENT if grep { $_ == DEPENDENT } @_;
76 return UNKNOWN;
79 sub max_state_alt {
80 return CRITICAL if grep { $_ == CRITICAL } @_;
81 return WARNING if grep { $_ == WARNING } @_;
82 return UNKNOWN if grep { $_ == UNKNOWN } @_;
83 return DEPENDENT if grep { $_ == DEPENDENT } @_;
84 return OK if grep { $_ == OK } @_;
85 return UNKNOWN;
88 # plugin_exit( $code, $message )
89 sub plugin_exit {
90 my ($code, $message, $arg) = @_;
92 # Handle named parameters
93 if (defined $code && ($code eq 'return_code' || $code eq 'message')) {
94 # Remove last argument if odd no and last is ref
95 if (int(@_ / 2) != @_ / 2 && ref $_[$#_]) {
96 $arg = pop @_;
97 } else {
98 undef $arg;
100 my %arg = @_;
101 $code = $arg{return_code};
102 $message = $arg{message};
104 $arg ||= {};
106 # Handle string codes
107 $code = $ERRORS{$code} if defined $code && exists $ERRORS{$code};
109 # Set defaults
110 $code = UNKNOWN unless defined $code && exists $STATUS_TEXT{$code};
111 $message = '' unless defined $message;
112 if (ref $message && ref $message eq 'ARRAY') {
113 $message = join(' ', map { chomp; $_ } @$message);
115 else {
116 chomp $message;
119 # Setup output
120 my $output = "$STATUS_TEXT{$code}";
121 if (defined $message && $message ne '') {
122 $output .= " - " unless $message =~ /^\s*\n/mxs;
123 $output .= $message;
125 my $shortname = ($arg->{plugin} ? $arg->{plugin}->shortname : undef);
126 $shortname ||= get_shortname(); # Should happen only if funnctions are called directly
127 $output = "$shortname $output" if $shortname;
128 if ($arg->{plugin}) {
129 my $plugin = $arg->{plugin};
130 $output .= " | ". $plugin->all_perfoutput
131 if $plugin->perfdata && $plugin->all_perfoutput;
133 $output .= "\n";
135 # Don't actually exit if _fake_exit set
136 if ($_fake_exit) {
137 require Monitoring::Plugin::ExitResult;
138 return Monitoring::Plugin::ExitResult->new($code, $output);
141 _plugin_exit($code, $output);
144 sub _plugin_exit {
145 my ($code, $output) = @_;
146 # Print output and exit; die if flag set and called via a die in stack backtrace
147 if ($_use_die) {
148 for (my $i = 0;; $i++) {
149 @_ = caller($i);
150 last unless @_;
151 if ($_[3] =~ m/die/) {
152 $! = $code;
153 die($output);
157 print $output;
158 exit $code;
161 # plugin_die( $message, [ $code ]) OR plugin_die( $code, $message )
162 # Default $code: UNKNOWN
163 sub plugin_die {
164 my ($arg1, $arg2, $rest) = @_;
166 # Named parameters
167 if (defined $arg1 && ($arg1 eq 'return_code' || $arg1 eq 'message')) {
168 return plugin_exit(@_);
171 # ($code, $message)
172 elsif (defined $arg1 && (exists $ERRORS{$arg1} || exists $STATUS_TEXT{$arg1})) {
173 return plugin_exit(@_);
176 # ($message, $code)
177 elsif (defined $arg2 && (exists $ERRORS{$arg2} || exists $STATUS_TEXT{$arg2})) {
178 return plugin_exit($arg2, $arg1, $rest);
181 # Else just assume $arg1 is the message and hope for the best
182 else {
183 return plugin_exit( UNKNOWN, $arg1, $arg2 );
187 # For backwards compatibility
188 sub die { plugin_die(@_); }
191 # ------------------------------------------------------------------------
192 # Utility functions
194 # Simple wrapper around Math::Calc::Units::convert
195 sub convert
197 my ($value, $from, $to) = @_;
198 my ($newval) = Math::Calc::Units::convert("$value $from", $to, 'exact');
199 return $newval;
202 # ------------------------------------------------------------------------
203 # check_messages - return a status and/or message based on a set of
204 # message arrays.
205 # Returns a nagios status code in scalar context.
206 # Returns a code and a message in list context.
207 # The message is join($join, @array) for the relevant array for the code,
208 # or join($join_all, $message) for all arrays if $join_all is set.
209 sub check_messages {
210 my %arg = validate( @_, {
211 critical => { type => ARRAYREF },
212 warning => { type => ARRAYREF },
213 ok => { type => ARRAYREF | SCALAR, optional => 1 },
214 'join' => { default => ' ' },
215 join_all => 0,
217 $arg{join} = ' ' unless defined $arg{join};
219 # Decide $code
220 my $code = OK;
221 $code ||= CRITICAL if @{$arg{critical}};
222 $code ||= WARNING if @{$arg{warning}};
223 return $code unless wantarray;
225 # Compose message
226 my $message = '';
227 if ($arg{join_all}) {
228 $message = join( $arg{join_all},
229 map { @$_ ? join( $arg{'join'}, @$_) : () }
230 $arg{critical},
231 $arg{warning},
232 $arg{ok} ? (ref $arg{ok} ? $arg{ok} : [ $arg{ok} ]) : []
236 else {
237 $message ||= join( $arg{'join'}, @{$arg{critical}} )
238 if $code == CRITICAL;
239 $message ||= join( $arg{'join'}, @{$arg{warning}} )
240 if $code == WARNING;
241 $message ||= ref $arg{ok} ? join( $arg{'join'}, @{$arg{ok}} ) : $arg{ok}
242 if $arg{ok};
245 return ($code, $message);
248 # ------------------------------------------------------------------------
252 # vim:sw=4:sm:et
254 __END__
256 =head1 NAME
258 Monitoring::Plugin::Functions - functions to simplify the creation of
259 Nagios plugins
261 =head1 SYNOPSIS
263 # Constants OK, WARNING, CRITICAL, and UNKNOWN exported by default
264 use Monitoring::Plugin::Functions;
266 # plugin_exit( CODE, $message ) - exit with error code CODE,
267 # and message "PLUGIN CODE - $message"
268 plugin_exit( CRITICAL, $critical_error ) if $critical_error;
269 plugin_exit( WARNING, $warning_error ) if $warning_error;
270 plugin_exit( OK, $result );
272 # plugin_die( $message, [$CODE] ) - just like plugin_exit(),
273 # but CODE is optional, defaulting to UNKNOWN
274 do_something()
275 or plugin_die("do_something() failed horribly");
276 do_something_critical()
277 or plugin_die("do_something_critical() failed", CRITICAL);
279 # check_messages - check a set of message arrays, returning a
280 # CODE and/or a result message
281 $code = check_messages(critical => \@crit, warning => \@warn);
282 ($code, $message) = check_messages(
283 critical => \@crit, warning => \@warn,
284 ok => \@ok );
286 # get_shortname - return the default short name for this plugin
287 # (as used by plugin_exit/die; not exported by default)
288 $shortname = get_shortname();
291 =head1 DESCRIPTION
293 This module is part of the Monitoring::Plugin family, a set of modules
294 for simplifying the creation of Nagios plugins. This module exports
295 convenience functions for the class methods provided by
296 Monitoring::Plugin. It is intended for those who prefer a simpler
297 functional interface, and who do not need the additional
298 functionality of Monitoring::Plugin.
300 =head2 EXPORTS
302 Nagios status code constants are exported by default:
305 WARNING
306 CRITICAL
307 UNKNOWN
308 DEPENDENT
310 as are the following functions:
312 plugin_exit
313 plugin_die
314 check_messages
316 The following variables and functions are exported only on request:
318 %ERRORS
319 %STATUS_TEXT
320 get_shortname
321 max_state
322 max_state_alt
325 =head2 FUNCTIONS
327 The following functions are supported:
329 =over 4
331 =item plugin_exit( <CODE>, $message )
333 Exit with return code CODE, and a standard nagios message of the
334 form "PLUGIN CODE - $message".
336 =item plugin_die( $message, [CODE] )
338 Same as plugin_exit(), except that CODE is optional, defaulting
339 to UNKNOWN. NOTE: exceptions are not raised by default to calling code.
340 Set C<$_use_die> flag if this functionality is required (see test code).
342 =item check_messages( critical => \@crit, warning => \@warn )
344 Convenience function to check a set of message arrays and return
345 an appropriate nagios return code and/or a result message. Returns
346 only a return code in scalar context; returns a return code and an
347 error message in list context i.e.
349 # Scalar context
350 $code = check_messages(critical => \@crit, warning => \@warn);
351 # List context
352 ($code, $msg) = check_messages(critical => \@crit, warning => \@warn);
354 check_messages() accepts the following named arguments:
356 =over 4
358 =item critical => ARRAYREF
360 An arrayref of critical error messages - check_messages() returns
361 CRITICAL if this arrayref is non-empty. Mandatory.
363 =item warning => ARRAYREF
365 An arrayref of warning error messages - check_messages() returns
366 WARNING if this arrayref is non-empty ('critical' is checked
367 first). Mandatory.
369 =item ok => ARRAYREF | SCALAR
371 An arrayref of informational messages (or a single scalar message),
372 used in list context if both the 'critical' and 'warning' arrayrefs
373 are empty. Optional.
375 =item join => SCALAR
377 A string used to join the relevant array to generate the message
378 string returned in list context i.e. if the 'critical' array @crit
379 is non-empty, check_messages would return:
381 join( $join, @crit )
383 as the result message. Optional; default: ' ' (space).
385 =item join_all => SCALAR
387 By default, only one set of messages are joined and returned in the
388 result message i.e. if the result is CRITICAL, only the 'critical'
389 messages are included in the result; if WARNING, only the 'warning'
390 messages are included; if OK, the 'ok' messages are included (if
391 supplied) i.e. the default is to return an 'errors-only' type
392 message.
394 If join_all is supplied, however, it will be used as a string to
395 join the resultant critical, warning, and ok messages together i.e.
396 all messages are joined and returned.
398 =back
400 =item get_shortname
402 Return the default shortname used for this plugin i.e. the first
403 token reported by plugin_exit/plugin_die. The default is basically
405 uc basename( $ENV{PLUGIN_NAME} || $ENV{NAGIOS_PLUGIN} || $0 )
407 with any leading 'CHECK_' and trailing file suffixes removed.
409 get_shortname is not exported by default, so must be explicitly
410 imported.
412 =item max_state(@a)
414 Returns the worst state in the array. Order is: CRITICAL, WARNING, OK, UNKNOWN,
415 DEPENDENT
417 The typical usage of max_state is to initialise the state as UNKNOWN and use
418 it on the result of various test. If no test were performed successfully the
419 state will still be UNKNOWN.
421 =item max_state_alt(@a)
423 Returns the worst state in the array. Order is: CRITICAL, WARNING, UNKNOWN,
424 DEPENDENT, OK
426 This is a true definition of a max state (OK last) and should be used if the
427 internal tests performed can return UNKNOWN.
429 =back
431 =head1 SEE ALSO
433 Monitoring::Plugin; the nagios plugin developer guidelines at
434 https://www.monitoring-plugins.org/doc/guidelines.html.
436 =head1 AUTHOR
438 This code is maintained by the Monitoring Plugin Development Team: see
439 https://monitoring-plugins.org
441 =head1 COPYRIGHT AND LICENSE
443 Copyright (C) 2014 by Monitoring Plugin Team
444 Copyright (C) 2006-2014 by Nagios Plugin Development Team
446 This library is free software; you can redistribute it and/or modify
447 it under the same terms as Perl itself.
449 =cut