File Coverage

blib/lib/Plack/App/ServiceStatus.pm
Criterion Covered Total %
statement 64 79 81.0
branch 10 16 62.5
condition n/a
subroutine 15 17 88.2
pod 1 2 50.0
total 90 114 78.9


line stmt bran cond sub pod time code
1             package Plack::App::ServiceStatus;
2              
3             # ABSTRACT: Check and report status of various services needed by your app
4              
5             our $VERSION = '0.913'; # VERSION
6              
7 3     3   583664 use 5.024;
  3         12  
8 3     3   18 use strict;
  3         6  
  3         124  
9 3     3   22 use warnings;
  3         6  
  3         241  
10              
11 3     3   22 use base 'Class::Accessor::Fast';
  3         8  
  3         2045  
12             __PACKAGE__->mk_accessors(qw(app version checks show_hostname buildinfo _buildinfo_data));
13              
14 3     3   17800 use Try::Tiny;
  3         8565  
  3         242  
15 3     3   1829 use Plack::Response;
  3         62457  
  3         2225  
16 3     3   1765 use JSON::MaybeXS;
  3         65064  
  3         310  
17 3     3   2996 use Sys::Hostname qw(hostname);
  3         4830  
  3         341  
18 3     3   1701 use Module::Runtime qw(use_module);
  3         6950  
  3         25  
19 3     3   1992 use Log::Any qw($log);
  3         39878  
  3         23  
20 3     3   12177 use Path::Tiny;
  3         61698  
  3         297  
21 3     3   2158 use POSIX qw(strftime);
  3         30233  
  3         27  
22              
23             my $startup = time();
24              
25             sub new {
26 4     4 1 620791 my ( $class, %args ) = @_;
27              
28             my %attr =
29 4         19 map { $_ => delete $args{$_} } qw(app version show_hostname buildinfo);
  16         70  
30 4         45 $attr{checks} = [];
31              
32 4         25 while ( my ( $key, $value ) = each %args ) {
33 0         0 my $module;
34 0 0       0 if ( $key =~ /^\+/ ) {
35 0         0 $module = $key;
36 0         0 $module =~ s/^\+//;
37             }
38             else {
39 0         0 $module = 'Plack::App::ServiceStatus::' . $key;
40             }
41             try {
42 0     0   0 use_module($module);
43             push(
44             $attr{checks}->@*,
45             {
46 0         0 class => $module,
47             name => $key,
48             args => $value
49             }
50             );
51             }
52             catch {
53 0     0   0 $log->errorf( "%s: cannot init %s: %s", __PACKAGE__, $module, $_ );
54 0         0 };
55             }
56              
57 4 100       17 if ( my $buildinfo_file = $attr{buildinfo} ) {
58 3         6 my $buildinfo;
59 3 100       116 if ( -f $buildinfo_file ) {
60             $buildinfo =
61 2         6 eval { decode_json( path( $buildinfo_file )->slurp_utf8 ) };
  2         36  
62 2 100       2718 if ($@) {
63 1         6 $buildinfo = { status => 'error', message => $@ };
64             }
65             }
66             else {
67 1         9 $buildinfo = {
68             status => 'error',
69             message => 'cannot read buildinfo from ' . $buildinfo_file
70             };
71             }
72 3         15 $attr{_buildinfo_data} = $buildinfo
73             }
74              
75 4         36 return bless \%attr, $class;
76             }
77              
78             sub to_app {
79 4     4 0 11 my $self = shift;
80              
81 4 50       180 my $hostname = $self->show_hostname ? hostname() : '';
82              
83             my $app = sub {
84 4     4   18 my $env = shift;
85              
86 4         137 my $json = {
87             app => $self->app,
88             started_at_iso8601 => strftime( '%Y-%m-%dT%H:%M:%SZ', gmtime($startup) ),
89             started_at => $startup,
90             uptime => time() - $startup,
91             };
92 4         382 $json->{version} = $self->version;
93 4 50       35 $json->{hostname} = $hostname if $hostname;
94 4 100       109 $json->{buildinfo} = $self->_buildinfo_data if $self->_buildinfo_data;
95              
96 4         191 my @results = (
97             {
98             name => $self->app,
99             status => 'ok',
100             }
101             );
102              
103 4         35 foreach my $check ( @{ $self->checks } ) {
  4         102  
104             my ( $status, $message ) = try {
105 0         0 return $check->{class}->check( $check->{args} );
106             }
107             catch {
108 0         0 return 'nok', "$_";
109 0         0 };
110             my $result = {
111             name => $check->{name},
112 0         0 status => $status,
113             };
114 0 0       0 $result->{message} = $message if ($message);
115              
116 0         0 push( @results, $result );
117             }
118 4         36 $json->{checks} = \@results;
119              
120 4         135 return Plack::Response->new( 200,
121             [ 'Content-Type', 'application/json' ],
122             encode_json($json) )->finalize;
123 4         80 };
124 4         14 return $app;
125             }
126              
127             1;
128              
129             __END__