File Coverage

blib/lib/Linux/Info/Compilation.pm
Criterion Covered Total %
statement 94 125 75.2
branch 35 74 47.3
condition 2 9 22.2
subroutine 15 15 100.0
pod 4 4 100.0
total 150 227 66.0


line stmt bran cond sub pod time code
1             package Linux::Info::Compilation;
2 15     15   700 use strict;
  15         33  
  15         441  
3 15     15   78 use warnings;
  15         36  
  15         503  
4 15     15   87 use Carp qw(croak);
  15         32  
  15         1751  
5              
6             our $VERSION = '1.3'; # VERSION
7              
8             =head1 NAME
9              
10             Linux::Info::Compilation - Statistics compilation.
11              
12             =head1 SYNOPSIS
13              
14             use Linux::Info;
15              
16             my $lxs = Linux::Info->new( loadavg => 1 );
17             my $stat = $lxs->get;
18              
19             foreach my $key ($stat->loadavg) {
20             print $key, " ", $stat->loadavg($key), "\n";
21             }
22              
23             # or
24              
25             use Linux::Info::LoadAVG;
26             use Linux::Info::Compilation;
27              
28             my $lxs = Linux::Info::LoadAVG->new();
29             my $load = $lxs->get;
30             my $stat = Linux::Info::Compilation->new({ loadavg => $load });
31              
32             foreach my $key ($stat->loadavg) {
33             print $key, " ", $stat->loadavg($key), "\n";
34             }
35              
36             # or
37              
38             foreach my $key ($stat->loadavg) {
39             print $key, " ", $stat->loadavg->{$key}, "\n";
40             }
41              
42             =head1 DESCRIPTION
43              
44             This module provides different methods to access and filter the statistics compilation.
45              
46             =head1 METHODS
47              
48             =head2 new()
49              
50             Create a new C object. This creator is only useful if you
51             don't call C of C. You can create a new object with:
52              
53             my $lxs = Linux::Info::LoadAVG->new();
54             my $load = $lxs->get;
55             my $stat = Linux::Info::Compilation->new({ loadavg => $load });
56              
57             =head2 Statistic methods
58              
59             =over
60              
61             =item sysinfo()
62              
63             =item cpustats()
64              
65             =item procstats()
66              
67             =item memstats()
68              
69             =item pgswstats()
70              
71             =item netstats()
72              
73             =item netinfo()
74              
75             C provides raw data - no deltas.
76              
77             =item sockstats()
78              
79             =item diskstats()
80              
81             =item diskusage()
82              
83             =item loadavg()
84              
85             =item filestats()
86              
87             =item processes()
88              
89             =back
90              
91             All methods returns the statistics as a hash reference in scalar context. In list all methods
92             returns the first level keys of the statistics. Example:
93              
94             my $net = $stat->netstats; # netstats as a hash reference
95             my @dev = $stat->netstats; # the devices eth0, eth1, ...
96             my $eth0 = $stat->netstats('eth0'); # eth0 statistics as a hash reference
97             my @keys = $stat->netstats('eth0'); # the statistic keys
98             my @vals = $stat->netstats('eth0', @keys); # the values for the passed device and @keys
99             my $val = $stat->netstats('eth0', $key); # the value for the passed device and key
100              
101             Sorted ...
102              
103             my @dev = sort $stat->netstats;
104             my @keys = sort $stat->netstats('eth0');
105              
106             =head2 pstop()
107              
108             This method is looking for top processes and returns a sorted list of PIDs as an array or
109             array reference depending on the context. It expected two values: a key name and the number
110             of top processes to return.
111              
112             As example you want to get the top 5 processes with the highest cpu usage:
113              
114             my @top5 = $stat->pstop( ttime => 5 );
115             # or as a reference
116             my $top5 = $stat->pstop( ttime => 5 );
117              
118             If you want to get all processes:
119              
120             my @top_all = $stat->pstop( ttime => $FALSE );
121             # or just
122             my @top_all = $stat->pstop( 'ttime' );
123              
124             =head2 search(), psfind()
125              
126             Both methods provides a simple scan engine to find special statistics. Both methods except a filter
127             as a hash reference. It's possible to pass the statistics as second argument if the data is not stored
128             in the object.
129              
130             The method C scans for statistics and rebuilds the hash tree until that keys that matched
131             your filter and returns the hits as a hash reference.
132              
133             my $hits = $stat->search({
134             processes => {
135             cmd => qr/\[su\]/,
136             owner => qr/root/
137             },
138             cpustats => {
139             idle => 'lt:10',
140             iowait => 'gt:10'
141             },
142             diskusage => {
143             '/dev/sda1' => {
144             usageper => 'gt:80'
145             }
146             }
147             });
148              
149             This would return the following matches:
150              
151             * processes with the command "[su]"
152             * processes with the owner "root"
153             * all cpu where "idle" is less than 50
154             * all cpu where "iowait" is grather than 10
155             * only disk '/dev/sda1' if "usageper" is grather than 80
156              
157             The method C scans for processes only and returns a array reference with all process
158             IDs that matched the filter. Example:
159              
160             my $pids = $stat->psfind({ cmd => qr/init/, owner => 'eq:apache' });
161              
162             This would return the following process ids:
163              
164             * processes that matched the command "init"
165             * processes with the owner "apache"
166              
167             There are different match operators available:
168              
169             gt - grather than
170             lt - less than
171             eq - is equal
172             ne - is not equal
173              
174             Notation examples:
175              
176             gt:50
177             lt:50
178             eq:50
179             ne:50
180              
181             Both argumnents have to be set as a hash reference.
182              
183             Note: the operators < > = ! are not available any more. It's possible that in further releases
184             could be different changes for C and C. So please take a look to the
185             documentation if you use it.
186              
187             =head1 EXPORTS
188              
189             Nothing.
190              
191             =head1 SEE ALSO
192              
193             =over
194              
195             =item *
196              
197             B
198              
199             =item *
200              
201             L
202              
203             =back
204              
205             =head1 AUTHOR
206              
207             Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
208              
209             =head1 COPYRIGHT AND LICENSE
210              
211             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
212              
213             This file is part of Linux Info project.
214              
215             Linux-Info is free software: you can redistribute it and/or modify
216             it under the terms of the GNU General Public License as published by
217             the Free Software Foundation, either version 3 of the License, or
218             (at your option) any later version.
219              
220             Linux-Info is distributed in the hope that it will be useful,
221             but WITHOUT ANY WARRANTY; without even the implied warranty of
222             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
223             GNU General Public License for more details.
224              
225             You should have received a copy of the GNU General Public License
226             along with Linux Info. If not, see .
227              
228             =cut
229              
230             # Creating the statistics accessors
231             BEGIN {
232 15     15   64 foreach
233             my $stat (qw/sysinfo procstats memstats sockstats loadavg filestats/)
234             {
235             ## no critic
236 15     15   100 no strict 'refs';
  15         37  
  15         933  
237 90         402 *{$stat} = sub {
238 15     15   99 use strict 'refs';
  15         139  
  15         1795  
239 33     33   7583 my ( $self, @keys ) = @_;
240 33 50       141 return () unless $self->{$stat};
241 33 50       91 if (@keys) {
242 0         0 return @{ $self->{$stat} }{@keys};
  0         0  
243             }
244 33 50       199 return wantarray ? keys %{ $self->{$stat} } : $self->{$stat};
  0         0  
245 90         387 };
246             ## use critic
247             }
248 15         40 foreach my $stat (
249             qw/cpustats pgswstats netstats netinfo diskstats diskusage processes/)
250             {
251             ## no critic
252 15     15   102 no strict 'refs';
  15         34  
  15         552  
253 105         12930 *{$stat} = sub {
254 15     15   82 use strict 'refs';
  15         28  
  15         1902  
255 96     96   42959 my ( $self, $sub, @keys ) = @_;
256 96 50       376 return () unless $self->{$stat};
257 96 50       240 if ($sub) {
258 0         0 my $ref = $self->{$stat};
259 0 0       0 return () unless exists $ref->{$sub};
260 0 0       0 if (@keys) {
261 0         0 return @{ $ref->{$sub} }{@keys};
  0         0  
262             }
263             else {
264 0 0       0 return wantarray ? keys %{ $ref->{$sub} } : $ref->{$sub};
  0         0  
265             }
266             }
267 96 50       565 return wantarray ? keys %{ $self->{$stat} } : $self->{$stat};
  0         0  
268 105         328 };
269             }
270             ## use critic
271             }
272              
273             sub new {
274 14     14 1 730 my ( $class, $stats ) = @_;
275 14 50       78 unless ( ref($stats) eq 'HASH' ) {
276 0         0 croak 'Usage: $class->new( \%statistics )';
277             }
278 14         76 return bless $stats, $class;
279             }
280              
281             sub search {
282 2     2 1 27 my $self = shift;
283 2 50       7 my $filter = ref( $_[0] ) eq 'HASH' ? shift : {@_};
284 2         6 my $class = ref($self);
285 2         5 my %hits = ();
286              
287 2         4 foreach my $opt ( keys %{$filter} ) {
  2         8  
288              
289 5 50       16 unless ( ref( $filter->{$opt} ) eq 'HASH' ) {
290 0         0 croak "$class: not a hash ref opt '$opt'";
291             }
292              
293             # next if the object isn't loaded
294 5 50       18 next unless exists $self->{$opt};
295 5         11 my $fref = $filter->{$opt};
296 5         22 my $proc = $self->{$opt};
297 5         10 my $subref;
298              
299             # we search for matches for each key that is defined
300             # in %filter and rebuild the tree until that key that
301             # matched the searched string
302              
303 5         7 foreach my $x ( keys %{$fref} ) {
  5         20  
304 10 50       25 if ( ref( $fref->{$x} ) eq 'HASH' ) {
305              
306             # if the key $proc->{eth0} doesn't exists
307             # then we continue with the next defined filter
308 0 0       0 next unless exists $proc->{$x};
309 0         0 $subref = $proc->{$x};
310              
311 0         0 while ( my ( $name, $value ) = each %{ $fref->{$x} } ) {
  0         0  
312 0 0 0     0 if ( exists $subref->{$name}
313             && $self->_compare( $subref->{$name}, $value ) )
314             {
315 0         0 $hits{$opt}{$x}{$name} = $subref->{$name};
316             }
317             }
318             }
319             else {
320 10         15 foreach my $key ( keys %{$proc} ) {
  10         31  
321 25 100       61 if ( ref( $proc->{$key} ) eq 'HASH' ) {
322 23         42 $subref = $proc->{$key};
323 23 50 33     100 if ( ref $subref->{$x} eq 'HASH' ) {
    50          
324 0         0 foreach my $y ( keys %{ $subref->{$x} } ) {
  0         0  
325 0 0       0 if (
326             $self->_compare(
327             $subref->{$x}->{$y},
328             $fref->{$x}
329             )
330             )
331             {
332             $hits{$opt}{$key}{$x}{$y} =
333 0         0 $subref->{$x}->{$y};
334             }
335             }
336             }
337             elsif ( defined $subref->{$x}
338             && $self->_compare( $subref->{$x}, $fref->{$x} ) )
339             {
340 23         90 $hits{$opt}{$key}{$x} = $subref->{$x};
341             }
342             }
343             else { # must be a scalar now
344 2 50 33     13 if ( defined $proc->{$x}
345             && $self->_compare( $proc->{$x}, $fref->{$x} ) )
346             {
347 2         10 $hits{$opt}{$x} = $proc->{$x};
348             }
349 2         9 last;
350             }
351             }
352             }
353             }
354             }
355              
356 2 50       10 return wantarray ? %hits : \%hits;
357             }
358              
359             sub psfind {
360 1     1 1 1551 my $self = shift;
361 1 50       7 my $filter = ref( $_[0] ) eq 'HASH' ? shift : {@_};
362 1 50       7 my $proc = $self->{processes} or return;
363 1         4 my @hits = ();
364              
365 1         3 PID: foreach my $pid ( keys %{$proc} ) {
  1         7  
366 10         25 my $proc = $proc->{$pid};
367 10         23 while ( my ( $key, $value ) = each %{$filter} ) {
  10         45  
368 5 50       19 if ( exists $proc->{$key} ) {
369 5 50       25 if ( ref $proc->{$key} eq 'HASH' ) {
    50          
370 0         0 foreach my $v ( values %{ $proc->{$key} } ) {
  0         0  
371 0 0       0 if ( $self->_compare( $v, $value ) ) {
372 0         0 push @hits, $pid;
373 0         0 next PID;
374             }
375             }
376             }
377             elsif ( $self->_compare( $proc->{$key}, $value ) ) {
378 5         18 push @hits, $pid;
379 5         17 next PID;
380             }
381             }
382             }
383             }
384              
385 1 50       9 return wantarray ? @hits : \@hits;
386             }
387              
388             sub pstop {
389 1     1 1 1681 my ( $self, $key, $count ) = @_;
390 1 50       6 unless ($key) {
391 0         0 croak 'Usage: pstop( $key => $count )';
392             }
393 1         4 my $proc = $self->{processes};
394             my @top = (
395 10         36 map { $_->[0] }
396 19         53 reverse sort { $a->[1] <=> $b->[1] }
397 1         4 map { [ $_, $proc->{$_}->{$key} ] } keys %{$proc}
  10         42  
  1         6  
398             );
399 1 50       9 if ($count) {
400 1         7 @top = @top[ 0 .. --$count ];
401             }
402 1 50       10 return wantarray ? @top : \@top;
403             }
404              
405             #
406             # private stuff
407             #
408              
409             sub _compare {
410 30     30   74 my ( $self, $x, $y ) = @_;
411              
412 30 100       163 if ( ref($y) eq 'Regexp' ) {
    100          
    100          
    100          
    50          
413 6         58 return $x =~ $y;
414             }
415             elsif ( $y =~ s/^eq:// ) {
416 1         6 return $x eq $y;
417             }
418             elsif ( $y =~ s/^ne:// ) {
419 2         11 return $x ne $y;
420             }
421             elsif ( $y =~ s/^gt:// ) {
422 3         20 return $x > $y;
423             }
424             elsif ( $y =~ s/^lt:// ) {
425 18         93 return $x < $y;
426             }
427             else {
428 0           croak ref($self) . ": bad search() / psfind() operator '$y'";
429             }
430              
431 0           return;
432             }
433              
434             1;