File Coverage

blib/lib/Proc/PidFile/Info.pm
Criterion Covered Total %
statement 68 72 94.4
branch 24 34 70.5
condition 4 9 44.4
subroutine 13 14 92.8
pod 6 6 100.0
total 115 135 85.1


line stmt bran cond sub pod time code
1             package Proc::PidFile::Info;
2             # ABSTRACT: gather proces info from PID files
3              
4 2     2   25246 use strict;
  2         4  
  2         76  
5 2     2   10 use warnings;
  2         5  
  2         68  
6              
7 2     2   20 use constant DEFAULT_LOCATION => '/var/run';
  2         5  
  2         164  
8 2     2   12 use constant DEFAULT_INFO_LEVEL => 0;
  2         3  
  2         89  
9 2     2   10 use constant DEFAULT_AUTOSCAN => 1;
  2         29  
  2         94  
10              
11 2     2   10 use constant STAT_CTIME => 10;
  2         2  
  2         2080  
12              
13             sub new
14             {
15 2     2 1 109 my $class = shift;
16 2         6 my %args = @_;
17              
18 2         3 my $self;
19              
20 2 50       17 $self->{locations} = exists $args{locations} ? ( ref($args{locations}) eq 'ARRAY' ) ? $args{locations} : [ $args{locations} ] : [ DEFAULT_LOCATION ];
    100          
21 2 100       6 $self->{info_level} = exists $args{info_level} ? $args{info_level} : DEFAULT_INFO_LEVEL;
22 2 100       8 $self->{autoscan} = exists $args{autoscan} ? $args{autoscan} : DEFAULT_AUTOSCAN;
23              
24 2         4 $self->{pidfiles} = [];
25              
26 2         5 bless $self, $class;
27              
28 2 100       14 $self->scan() if $self->{autoscan};
29 2         8 return $self;
30             }
31              
32              
33 2     2 1 13 sub info_level { return $_[0]->{info_level} }
34              
35 0     0 1 0 sub autoscan { return $_[0]->{autoscan} }
36              
37 2 50   2 1 1646 sub locations { return wantarray ? @{$_[0]->{pidfiles}}:$_[0]->{locations} }
  0         0  
38              
39 3 100   3 1 16 sub pidfiles { return wantarray ? @{$_[0]->{pidfiles}} : $_[0]->{pidfiles} }
  2         21  
40              
41             sub scan
42             {
43 2     2 1 7 my $self = shift;
44              
45 2         4 my @files;
46              
47 2         7 foreach my $location (@{$self->{locations}}) {
  2         14  
48 4 100 66     171 if (-d $location and -r $location) {
    50 33        
49 2         17 push @files, _collect_files( $location );
50             }
51             elsif (-f $location and -r $location) {
52 2         15 push @files, $location;
53             }
54             else {
55             # invalid location, skip
56             }
57             }
58              
59 2         14 $self->{pidfiles} = [ $self->_collect_info( @files ) ];
60              
61 2         32 return 1;
62             }
63              
64             sub _collect_files
65             {
66 2     2   9 my $dir = shift;
67              
68 2 50       129 opendir(my $dh, $dir) or die "Can not open directory $dir for reading: $!";
69 2         5 my (@files);
70 2         54 while(my $entry = readdir($dh)) {
71 11 100       45 next if $entry =~ /^\./;
72 7 50       38 next unless $entry =~ /\.pid$/;
73 7         16 my $file = "$dir/$entry";
74 7 50 33     271 next unless -f $file and -r $file;
75 7         39 push @files, $file;
76             }
77              
78 2         39 return @files;
79             }
80              
81             sub _collect_info
82             {
83 2     2   7 my ($self, @files) = @_;
84              
85 2         3 my @info;
86              
87 2         6 foreach my $file (@files) {
88 9         33 my $info = { path => $file };
89 9 50       57 if ($file =~ m{([^/]+)\.pid$}) {
90 9         71 $info->{name} = $1;
91             }
92             else {
93 0         0 die "Invalid PID filename: $file";
94             }
95              
96 9 50       34 if ($self->{info_level} == 0) { # info level 0 : ctime of pid file
    50          
97 0         0 $info->{ctime} = (stat($file))[STAT_CTIME];
98             }
99             elsif( $self->{info_level} >= 1) { # info level 1: ctime + PID
100 9 50       335 open( my $fh, '<', $file) or die "Can not open file $file for reading: $!";
101 9         92 $info->{ctime} = (stat($fh))[STAT_CTIME];
102 9         121 my $pid = <$fh>;
103 9         89 close $fh;
104              
105 9         15 chomp($pid);
106 9         29 $pid =~ s/^\s+//;
107 9         21 $pid =~ s/\s+$//;
108 9         39 $info->{pid} = $pid;
109             }
110             else {
111             # negative info level - skip
112             }
113 9         23 push @info, $info;
114             }
115              
116 2         12 return @info;
117             }
118              
119             1;
120              
121              
122             =pod
123              
124             =head1 NAME
125              
126             Proc::PidFile::Info - gather proces info from PID files
127              
128             =head1 VERSION
129              
130             version 0.02
131              
132             =head1 SYNOPSIS
133              
134             use Proc::PidFile::Info;
135              
136             my $info = Proc::PidFile::Info->new(
137             locations => [
138             '/var/run',
139             '/my/own/rundir/'
140             ],
141             info_level => 1,
142             );
143              
144             foreach my $pidfile ( $info->pidfiles() ) {
145             print "Service $pidfile->{name} running with PID $pidfile->{pid}, started on " . scalar( localtime ( $pidfile->{ctime} ) ) . "\n";
146             }
147              
148             =head1 DESCRIPTION
149              
150             This module scans a list of PID file locations and/or directories containing PID files (such as C) and gathers information
151             from the PID files it finds. The PID files must have a C<.pid> extension.
152              
153             The name of the file (with the C<.pid> extension stripped) is assumed to be the name of the service or daemon that created the PID
154             file. The creation time of the PID file is assumed to be the timestamp when the service or daemon was last (re)started. The module
155             can also read the PID from the PID file. The information gathered is returned as an array of hashes. Each hash describes the
156             information for a PID file and it's associated service or daemon.
157              
158             =head1 ATTRIBUTES
159              
160             =head2 locations
161              
162             Stores the locations in which the scanner searches for PID files. PID files must have a C<.pid> extension.
163              
164             Default value: C
165              
166             =head2 info_level
167              
168             Specifies how much information the scanner will gather from the PID files
169              
170             =over 4
171              
172             =item level 0
173              
174             Scans only file name and creation time. The info hashes will contain only the C and C keys.
175              
176             =item level 1
177              
178             Also opens each PID file and reads the PID from it. The info hashes will also contain the C key, in addition to level 0 keys.
179              
180             =back
181              
182             Default value: 0
183              
184             =head2 autoscan
185              
186             A boolean flag which causes the scanner to automatically initiate a scan after object construction.
187              
188             Default value: 1
189              
190             =head1 METHODS
191              
192             =head2 new
193              
194             Creates a new PID file scanner objects. Arguments are:
195              
196             =over 4
197              
198             =item locations
199              
200             A list of files and directories to scan. See C
201              
202             =item info_level
203              
204             How much detail to extract from PID files. See C
205              
206             =item autoscan
207              
208             If true, the scanner will perform a scan right after it is constructed. See C
209              
210             =back
211              
212             =head2 scan
213              
214             Scans all the locations and gathers PID file information. This method is automatically called on object initialization, if the
215             C property is set to true.
216              
217             =head2 pidfiles
218              
219             Returns the information gathered from the PID files. If the C property is set to false, you must call the L method
220             to gather the information first. Depending upon the calling context a list ot an array reference is returned.
221              
222             =head1 AUTHOR
223              
224             Christian-Rolf Gruen
225              
226             =head1 COPYRIGHT AND LICENSE
227              
228             This software is copyright (c) 2012 by Christian-Rolf Gruen.
229              
230             This is free software; you can redistribute it and/or modify it under
231             the same terms as the Perl 5 programming language system itself.
232              
233             =cut
234              
235              
236             __END__