File Coverage

blib/lib/HealthCheck/Diagnostic/RabbitMQ.pm
Criterion Covered Total %
statement 90 91 98.9
branch 38 42 90.4
condition 40 44 90.9
subroutine 11 11 100.0
pod 3 3 100.0
total 182 191 95.2


line stmt bran cond sub pod time code
1             package HealthCheck::Diagnostic::RabbitMQ;
2              
3             # ABSTRACT: Check connectivity and queues on a RabbitMQ server
4 1     1   106332 use version;
  1         2073  
  1         6  
5             our $VERSION = 'v1.1.6'; # VERSION
6              
7 1     1   107 use 5.010;
  1         7  
8 1     1   5 use strict;
  1         2  
  1         18  
9 1     1   5 use warnings;
  1         2  
  1         25  
10 1     1   482 use parent 'HealthCheck::Diagnostic';
  1         294  
  1         6  
11              
12 1     1   4811 use Carp;
  1         2  
  1         922  
13              
14             sub new {
15 7     7 1 2932 my ($class, @params) = @_;
16              
17             # Allow either a hashref or even-sized list of params
18             my %params = @params == 1 && ( ref $params[0] || '' ) eq 'HASH'
19 7 50 33     43 ? %{ $params[0] } : @params;
  0         0  
20              
21 7         36 return $class->SUPER::new(
22             label => 'rabbit_mq',
23             %params
24             );
25             }
26              
27             sub check {
28 30     30 1 13466 my ( $self, %params ) = @_;
29              
30             # The method the object needs to have for us to proceed
31 30         61 my $method = 'get_server_properties';
32              
33             # These are the params that we actually use to make our decisions
34             # and that we're going to return in the result to make that clear.
35 30         66 my %decision_params = ( rabbit_mq => undef );
36              
37 30         76 my @limits = qw(
38             listeners_min_critical
39             listeners_min_warning
40             listeners_max_critical
41             listeners_max_warning
42              
43             messages_critical
44             messages_warning
45             );
46              
47             # If we have a queue to check, that changes our requirements
48 30 100 100     128 if ( defined $params{queue}
      100        
49             or ( ref $self and defined $self->{queue} ) )
50             {
51 19         32 $method = 'queue_declare';
52 19         101 $decision_params{$_} = undef for qw(
53             queue
54             channel
55             ), @limits;
56             }
57              
58             # Now we prefer the params passed to check,
59             # and fall back to what is on the instance.
60 30         96 foreach my $param ( keys %decision_params ) {
61             $decision_params{$param}
62             = exists $params{$param} ? $params{$param}
63 182 100       399 : ref $self ? $self->{$param}
    100          
64             : undef;
65             }
66              
67             # No need to return the limits we aren't using in the result
68 30         75 delete @decision_params{ grep { !defined $decision_params{$_} } @limits };
  180         411  
69              
70             # The rabbit_mq param was only "known" so we could choose between
71             # one that was passed to check and the one on the instance.
72 30         59 my $rabbit_mq = delete $decision_params{rabbit_mq};
73 30         51 my $should_disconnect = 0;
74 30 100       83 if (ref $rabbit_mq eq 'CODE') {
75 9         17 local $@;
76 9         18 ($rabbit_mq, $should_disconnect) = eval {
77 9         31 local $SIG{__DIE__};
78 9         27 $rabbit_mq->(%params);
79             };
80 9 100       87 if ($@) {
81 1         8 return $self->summarize({ status => 'CRITICAL', info => "$@" })
82             }
83             }
84              
85 29 100 100     958 croak("'rabbit_mq' must have '$method' method") unless $rabbit_mq and do {
86 22         50 local $@; eval { local $SIG{__DIE__}; $rabbit_mq->can($method) } };
  22         43  
  22         68  
  22         342  
87              
88             # Any "should_disconnect" in the params or the instance should take
89             # precedence over what might have been returned by a coderef:
90             #
91             $should_disconnect = exists $params{should_disconnect}
92             ? $params{should_disconnect}
93             : (ref $self && exists $self->{should_disconnect})
94             ? $self->{should_disconnect}
95 20 50 66     79 : $should_disconnect;
    50          
96              
97             # In theory we could default to random channel in the
98             # range of 1..$rabbit_mq->get_max_channel
99             # but then we would have to:
100             # 1. Hope it's not in use
101             # 2. Open and then close it.
102             # Instead we default to 1 as that's what our internal code does.
103             $decision_params{channel} //= 1
104 20 100 100     81 if exists $decision_params{channel};
105              
106 20         91 my $res = $self->SUPER::check(
107             %params,
108             %decision_params,
109             rabbit_mq => $rabbit_mq,
110             should_disconnect => $should_disconnect,
111             );
112              
113             # Make sure we report what we actually *used*
114             # not what our parent may have copied out of %{ $self }
115 20 100       1112 $res->{data} = { %{ $res->{data} || {} }, %decision_params }
  16 100       95  
116             if %decision_params;
117 20         55 delete $res->{rabbit_mq}; # don't include the object in the result
118              
119 20         192 return $res;
120             }
121              
122             sub run {
123 20     20 1 522 my ( $self, %params ) = @_;
124 20         39 my $rabbit_mq = $params{rabbit_mq};
125              
126 20     4   72 my $cb = sub { $rabbit_mq->get_server_properties };
  4         10  
127              
128 20 100       51 if ( defined $params{queue} ) {
129 16         33 my $queue = $params{queue};
130 16         27 my $channel = $params{channel};
131              
132             $cb = sub {
133 16     16   58 my ( $name, $messages, $listeners )
134             = $rabbit_mq->queue_declare( $channel, $queue,
135             { passive => 1 } );
136              
137             return {
138 14         116 name => $name,
139             messages => $messages,
140             listeners => $listeners,
141             };
142 16         74 };
143             }
144              
145 20         33 my $data;
146             {
147 20         32 local $@;
  20         32  
148 20         36 eval {
149 20         72 local $SIG{__DIE__};
150 20         42 $data = $cb->();
151 16 50       64 $rabbit_mq->disconnect if $params{should_disconnect};
152             };
153              
154 20 100       888 if ( my $e = $@ ) {
155 4         10 my $file = quotemeta __FILE__;
156 4         67 $e =~ s/ at $file line \d+\.?\n\Z//ms;
157 4         17 $e =~ s/^Declaring queue: //;
158 4         42 return { status => 'CRITICAL', info => $e };
159             }
160             }
161              
162 16         44 my %res = ( status => 'OK', data => $data );
163              
164 16 100       42 if ( defined $data->{listeners} ) {
165 14         21 my $listeners = $data->{listeners};
166 14 100 100     121 if (( defined $params{listeners_max_critical}
    100 100        
      100        
      100        
      100        
      66        
167             and $params{listeners_max_critical} <= $listeners
168             )
169             or ( defined $params{listeners_min_critical}
170             and $params{listeners_min_critical} >= $listeners )
171             )
172             {
173 4         9 $res{status} = 'CRITICAL';
174 4         8 $res{info} = "Listeners out of range!";
175             }
176             elsif (
177             ( defined $params{listeners_max_warning}
178             and $params{listeners_max_warning} <= $listeners
179             )
180             or ( defined $params{listeners_min_warning}
181             and $params{listeners_min_warning} >= $listeners )
182             )
183             {
184 2         11 $res{status} = 'WARNING';
185 2         6 $res{info} = "Listeners out of range!";
186             }
187             }
188              
189 16 100 100     60 if ( $res{status} ne 'CRITICAL' and defined $data->{messages} ) {
190 10         16 my $messages = $data->{messages};
191 10 100 100     44 if ( defined $params{messages_critical}
    100 100        
192             and $params{messages_critical} <= $messages )
193             {
194 2         5 $res{status} = 'CRITICAL';
195 2         6 $res{info} = "Messages out of range!";
196             }
197             elsif ( defined $params{messages_warning}
198             and $params{messages_warning} <= $messages )
199             {
200 1         2 $res{status} = 'WARNING';
201 1         3 $res{info} = "Messages out of range!";
202             }
203             }
204              
205 16         102 return \%res;
206             }
207              
208             1;
209              
210             __END__