File Coverage

blib/lib/HealthCheck/Diagnostic/RabbitMQ.pm
Criterion Covered Total %
statement 102 104 98.0
branch 48 54 88.8
condition 40 44 90.9
subroutine 11 11 100.0
pod 3 3 100.0
total 204 216 94.4


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   108335 use version;
  1         2011  
  1         6  
5             our $VERSION = 'v1.3.0'; # VERSION
6              
7 1     1   143 use 5.010;
  1         7  
8 1     1   5 use strict;
  1         3  
  1         18  
9 1     1   5 use warnings;
  1         2  
  1         28  
10 1     1   621 use parent 'HealthCheck::Diagnostic';
  1         274  
  1         10  
11              
12 1     1   2643 use Carp;
  1         3  
  1         1089  
13              
14             sub new {
15 7     7 1 3222 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     42 ? %{ $params[0] } : @params;
  0         0  
20              
21 7         40 return $class->SUPER::new(
22             label => 'rabbit_mq',
23             %params
24             );
25             }
26              
27             sub check {
28 30     30 1 14091 my ( $self, %params ) = @_;
29              
30             # The method the object needs to have for us to proceed
31 30         65 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         64 my %decision_params = ( rabbit_mq => undef );
36              
37 30         90 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     123 if ( defined $params{queue}
      100        
49             or ( ref $self and defined $self->{queue} ) )
50             {
51 19         33 $method = 'queue_declare';
52 19         106 $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         97 foreach my $param ( keys %decision_params ) {
61             $decision_params{$param}
62             = exists $params{$param} ? $params{$param}
63 182 100       396 : 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         71 delete @decision_params{ grep { !defined $decision_params{$_} } @limits };
  180         440  
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         66 my $rabbit_mq = delete $decision_params{rabbit_mq};
73 30         51 my $should_disconnect = 0;
74 30 100       86 if (ref $rabbit_mq eq 'CODE') {
75 9         14 local $@;
76 9         20 ($rabbit_mq, $should_disconnect) = eval {
77 9         29 local $SIG{__DIE__};
78 9         30 $rabbit_mq->(%params);
79             };
80 9 100       89 if ($@) {
81 1         8 return $self->summarize({ status => 'CRITICAL', info => "$@" })
82             }
83             }
84              
85 29 100 100     967 croak("'rabbit_mq' must have '$method' method") unless $rabbit_mq and do {
86 22         47 local $@; eval { local $SIG{__DIE__}; $rabbit_mq->can($method) } };
  22         54  
  22         71  
  22         402  
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     88 : $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     82 if exists $decision_params{channel};
105              
106 20         97 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       1124 $res->{data} = { %{ $res->{data} || {} }, %decision_params }
  16 100       96  
116             if %decision_params;
117 20         51 delete $res->{rabbit_mq}; # don't include the object in the result
118              
119 20         239 return $res;
120             }
121              
122             sub run {
123 20     20 1 502 my ( $self, %params ) = @_;
124 20         35 my $rabbit_mq = $params{rabbit_mq};
125              
126 20     4   76 my $cb = sub { $rabbit_mq->get_server_properties };
  4         11  
127              
128 20 100       59 if ( defined $params{queue} ) {
129 16         31 my $queue = $params{queue};
130 16         28 my $channel = $params{channel};
131              
132             $cb = sub {
133 16     16   61 my ( $name, $messages, $listeners )
134             = $rabbit_mq->queue_declare( $channel, $queue,
135             { passive => 1 } );
136              
137 14         100 my $server_properties;
138 14 50       48 if ($rabbit_mq->can("get_server_properties")) {
139 0         0 $server_properties = $rabbit_mq->get_server_properties;
140             }
141              
142             return {
143 14 50       53 ( $server_properties
144             ? (server_properties => $server_properties)
145             : ()
146             ),
147             name => $name,
148             messages => $messages,
149             listeners => $listeners,
150             };
151 16         75 };
152             }
153              
154 20         35 my $data;
155             {
156 20         36 local $@;
  20         29  
157 20         39 eval {
158 20         52 local $SIG{__DIE__};
159 20         41 $data = $cb->();
160 16 50       65 $rabbit_mq->disconnect if $params{should_disconnect};
161             };
162              
163 20 100       908 if ( my $e = $@ ) {
164 4         20 my $file = quotemeta __FILE__;
165 4         70 $e =~ s/ at $file line \d+\.?\n\Z//ms;
166 4         18 $e =~ s/^Declaring queue: //;
167 4         59 return { status => 'CRITICAL', info => $e };
168             }
169             }
170              
171 16         46 my %res = ( status => 'OK', data => $data );
172              
173 16 100       42 if ( defined $data->{listeners} ) {
174 14         35 my $listeners = $data->{listeners};
175 14 100 100     135 if (( defined $params{listeners_max_critical}
    100 100        
      100        
      100        
      100        
      66        
176             and $params{listeners_max_critical} <= $listeners
177             )
178             or ( defined $params{listeners_min_critical}
179             and $params{listeners_min_critical} >= $listeners )
180             )
181             {
182 4         7 my $min = $params{listeners_min_critical};
183 4         9 my $max = $params{listeners_max_critical};
184 4         6 $res{status} = 'CRITICAL';
185 4         8 my $info = "Listeners out of range! Expected";
186 4 100       11 $info .= " min: $min" if defined $min;
187 4 100       11 $info .= " max: $max" if defined $max;
188 4         11 $res{info} = "$info have: $listeners";
189             }
190             elsif (
191             ( defined $params{listeners_max_warning}
192             and $params{listeners_max_warning} <= $listeners
193             )
194             or ( defined $params{listeners_min_warning}
195             and $params{listeners_min_warning} >= $listeners )
196             )
197             {
198 2         4 my $min = $params{listeners_min_warning};
199 2         5 my $max = $params{listeners_max_warning};
200 2         3 $res{status} = 'WARNING';
201 2         5 my $info = "Listeners out of range! Expected";
202 2 100       23 $info .= " min: $min" if defined $min;
203 2 100       11 $info .= " max: $max" if defined $max;
204 2         7 $res{info} = "$info have: $listeners";
205             }
206             }
207              
208 16 100 100     63 if ( $res{status} ne 'CRITICAL' and defined $data->{messages} ) {
209 10         18 my $messages = $data->{messages};
210 10 100 100     45 if ( defined $params{messages_critical}
    100 100        
211             and $params{messages_critical} <= $messages )
212             {
213 2         4 $res{status} = 'CRITICAL';
214             $res{info} = sprintf(
215             "Messages out of range! Expected max: %d have: %d",
216             $params{messages_critical},
217 2         12 $messages,
218             );
219             }
220             elsif ( defined $params{messages_warning}
221             and $params{messages_warning} <= $messages )
222             {
223 1         2 $res{status} = 'WARNING';
224             $res{info} = sprintf(
225             "Messages out of range! Expected max: %d have: %d",
226             $params{messages_warning},
227 1         6 $messages,
228             );
229             }
230             }
231              
232 16         106 return \%res;
233             }
234              
235             1;
236              
237             __END__