File Coverage

blib/lib/Monitor/Simple.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             #-----------------------------------------------------------------
2             # Monitor::Simple
3             # Author: Martin Senger
4             # For copyright and disclaimer se below.
5             #
6             # ABSTRACT: Simple monitoring of applications and services
7             # PODNAME: Monitor::Simple
8             #-----------------------------------------------------------------
9              
10             package Monitor::Simple;
11              
12 6     6   274522 use warnings;
  6         17  
  6         219  
13 6     6   34 use strict;
  6         12  
  6         369  
14              
15             our $VERSION = '0.2.8'; # VERSION
16              
17             # values returned by plugins (compatible with Nagios'
18             use constant {
19 6         834 RETURN_OK => 0,
20             RETURN_WARNING => 1,
21             RETURN_CRITICAL => 2,
22             RETURN_UNKNOWN => 3,
23              
24             # ...and this is returned if the plugin cannot be started
25             RETURN_FATAL => -1,
26 6     6   34 };
  6         8  
27              
28             # values used in configuration file for notifiers (in attribute "on")
29             use constant {
30 6         640 NOTIFY_OK => 'ok',
31             NOTIFY_WARNING => 'w',
32             NOTIFY_CRITICAL => 'c',
33             NOTIFY_UNKNOWN => 'u',
34             NOTIFY_ALL => 'all',
35             NOTIFY_ERRORS => 'err',
36             NOTIFY_NONE => 'none',
37 6     6   31 };
  6         14  
38              
39 6     6   3761 use Monitor::Simple::Log;
  6         18  
  6         220  
40 6     6   4174 use Monitor::Simple::Config;
  0            
  0            
41             use Monitor::Simple::UserAgent;
42             use Monitor::Simple::Utils;
43             use Monitor::Simple::Output;
44             use Monitor::Simple::Notifier;
45              
46             use Carp;
47             use Log::Log4perl qw(:easy);
48             use Parallel::ForkManager;
49             use IO::CaptureOutput qw(capture_exec);
50             use File::Spec;
51             use Time::HiRes qw(time);
52              
53              
54             my $default_npp = 10; # maximum number of child processes in parallel
55              
56             # -----------------------------------------------------------------
57             # The main loop checking all services as defined in the given
58             # configuration.
59             #
60             # Recognized arguments:
61             # { config_file => $config_file,
62             # npp => ,
63             # outputter => instance of Monitor::Simple::Output,
64             # filter => hashref (keys are service IDS) or
65             # arrayref with service IDs, or
66             # scalar with just one service ID
67             # nonotif => boolean
68             # }
69             # -----------------------------------------------------------------
70             sub check_services {
71             my ($self, $args) = @_;
72              
73             # recognized arguments
74             my $config;
75             my $config_file;
76             if ($args->{config_file}) {
77             $config_file = $args->{config_file};
78             $config = Monitor::Simple::Config->get_config ($config_file);
79             } else {
80             LOGDIE ("check_services: Missing argument 'config_file'. Cannot do anything.\n");
81             }
82             my $npp = ($args->{npp} || $default_npp);
83             if ($npp < 1) {
84             LOGWARN ("check_services: Argument 'npp' must be positive. Replaced by default value $default_npp.\n");
85             $npp = $default_npp;
86             }
87             my $outputter = ($args->{outputter} || Monitor::Simple::Output->new (config => $config));
88              
89             # optional filter tells which only services to check; filter can be
90             # hashref or arrayref or scalar (all with service name(s) we wish
91             # to check)
92             my $filter = $args->{filter};
93             if ($filter) {
94             if (ref ($filter) eq 'ARRAY') {
95             $filter = { map { $_ => 1 } @$filter };
96             } elsif (ref ($filter) eq 'HASH') {
97             # already done
98             } else {
99             $filter = { $filter => 1 };
100             }
101             }
102             $filter = undef unless keys %$filter > 0;
103              
104             # before the main checking loop starts
105             $outputter->header();
106             my $notifier = Monitor::Simple::Notifier->new (config => $config,
107             cfgfile => $config_file);
108              
109             # main loop
110             INFO ('--- Checking started ---');
111             my $start_time = time();
112             my $pm = new Parallel::ForkManager ($npp);
113             foreach my $service (@{ $config->{services} }) {
114              
115             # filtering of services
116             next if $filter and not exists $filter->{ $service->{id} };
117              
118             # this does the fork and for the parent branch and continues the foreach loop
119             $pm->start and next;
120              
121             # this is the child branch: execute an external plugin...
122             my $command = $service->{plugin}->{command};
123             unless (File::Spec->file_name_is_absolute ($command)) {
124             my $plugins_dir = $config->{general}->{'plugins-dir'};
125             if ($plugins_dir) {
126             $command = File::Spec->catfile ($plugins_dir, $command);
127             }
128             }
129             my @command = ($command,
130             Monitor::Simple::Config->create_plugin_args ($config_file,
131             $config,
132             $service->{id}));
133             DEBUG ("Started: " . join (' ', @command));
134             my ($stdout, $stderr, $success, $exit_code) = capture_exec (@command);
135              
136             # ...and make the result report
137             print STDERR "$stderr\n" if $stderr; # do not hide standard errors, if any
138             my ($code, $msg) = Monitor::Simple::Utils->process_exit ($command, $exit_code, $stdout);
139             $outputter->out ($service->{id}, $code, $msg);
140             unless (exists $args->{nonotif} and $args->{nonotif}) {
141             $notifier->notify ( { service => $service->{id},
142             code => $code,
143             msg => $msg } );
144             }
145             $pm->finish;
146             }
147              
148             # here the parent branch continue when all child process have been
149             # started; we need to wait untill all these processes finish -
150             # otherwise we would create a "zombie" process in out operating
151             # system
152             $pm->wait_all_children();
153             $outputter->footer();
154              
155             INFO ('--- Checking finished [' . (time() - $start_time) . ' s] ---');
156             }
157              
158              
159             1; # End of Monitor::Simple
160              
161             __END__