File Coverage

blib/lib/Linux/Info/Compilation.pm
Criterion Covered Total %
statement 94 125 75.2
branch 36 74 48.6
condition 3 9 33.3
subroutine 15 15 100.0
pod 4 4 100.0
total 152 227 66.9


line stmt bran cond sub pod time code
1             package Linux::Info::Compilation;
2 14     14   801 use strict;
  14         29  
  14         415  
3 14     14   67 use warnings;
  14         26  
  14         399  
4 14     14   66 use Carp qw(croak);
  14         26  
  14         1579  
5              
6             our $VERSION = '1.5'; # 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 14     14   89 foreach
233             my $stat (qw/sysinfo procstats memstats sockstats loadavg filestats/)
234             {
235             ## no critic
236 14     14   98 no strict 'refs';
  14         42  
  14         684  
237 84         367 *{$stat} = sub {
238 14     14   87 use strict 'refs';
  14         24  
  14         1937  
239 18     18   4600 my ( $self, @keys ) = @_;
240 18 50       113 return () unless $self->{$stat};
241 18 50       44 if (@keys) {
242 0         0 return @{ $self->{$stat} }{@keys};
  0         0  
243             }
244 18 50       96 return wantarray ? keys %{ $self->{$stat} } : $self->{$stat};
  0         0  
245 84         299 };
246             ## use critic
247             }
248 14         36 foreach my $stat (
249             qw/cpustats pgswstats netstats netinfo diskstats diskusage processes/)
250             {
251             ## no critic
252 14     14   96 no strict 'refs';
  14         26  
  14         581  
253 98         14843 *{$stat} = sub {
254 14     14   88 use strict 'refs';
  14         28  
  14         2080  
255 96     96   31437 my ( $self, $sub, @keys ) = @_;
256 96 50       356 return () unless $self->{$stat};
257              
258 96 50       192 if ($sub) {
259 0         0 my $ref = $self->{$stat};
260 0 0       0 return () unless exists $ref->{$sub};
261              
262 0 0       0 if (@keys) {
263 0         0 return @{ $ref->{$sub} }{@keys};
  0         0  
264             }
265             else {
266 0 0       0 return wantarray ? keys %{ $ref->{$sub} } : $ref->{$sub};
  0         0  
267             }
268             }
269 96 50       603 return wantarray ? keys %{ $self->{$stat} } : $self->{$stat};
  0         0  
270 98         376 };
271             }
272             ## use critic
273             }
274              
275             sub new {
276 13     13 1 1049 my ( $class, $stats ) = @_;
277 13 50       74 unless ( ref($stats) eq 'HASH' ) {
278 0         0 croak 'Usage: $class->new( \%statistics )';
279             }
280 13         128 return bless $stats, $class;
281             }
282              
283             sub search {
284 2     2 1 24 my $self = shift;
285 2 50       7 my $filter = ref( $_[0] ) eq 'HASH' ? shift : {@_};
286 2         4 my $class = ref($self);
287 2         5 my %hits = ();
288              
289 2         3 foreach my $opt ( keys %{$filter} ) {
  2         8  
290              
291 5 50       16 unless ( ref( $filter->{$opt} ) eq 'HASH' ) {
292 0         0 croak "$class: not a hash ref opt '$opt'";
293             }
294              
295             # next if the object isn't loaded
296 5 50       18 next unless exists $self->{$opt};
297 5         10 my $fref = $filter->{$opt};
298 5         8 my $proc = $self->{$opt};
299 5         8 my $subref;
300              
301             # we search for matches for each key that is defined
302             # in %filter and rebuild the tree until that key that
303             # matched the searched string
304              
305 5         7 foreach my $x ( keys %{$fref} ) {
  5         15  
306 10 50       24 if ( ref( $fref->{$x} ) eq 'HASH' ) {
307              
308             # if the key $proc->{eth0} doesn't exists
309             # then we continue with the next defined filter
310 0 0       0 next unless exists $proc->{$x};
311 0         0 $subref = $proc->{$x};
312              
313 0         0 while ( my ( $name, $value ) = each %{ $fref->{$x} } ) {
  0         0  
314 0 0 0     0 if ( exists $subref->{$name}
315             && $self->_compare( $subref->{$name}, $value ) )
316             {
317 0         0 $hits{$opt}{$x}{$name} = $subref->{$name};
318             }
319             }
320             }
321             else {
322 10         11 foreach my $key ( keys %{$proc} ) {
  10         26  
323 28 100       60 if ( ref( $proc->{$key} ) eq 'HASH' ) {
324 26         33 $subref = $proc->{$key};
325 26 50 66     84 if ( ref $subref->{$x} eq 'HASH' ) {
    100          
326 0         0 foreach my $y ( keys %{ $subref->{$x} } ) {
  0         0  
327 0 0       0 if (
328             $self->_compare(
329             $subref->{$x}->{$y},
330             $fref->{$x}
331             )
332             )
333             {
334             $hits{$opt}{$key}{$x}{$y} =
335 0         0 $subref->{$x}->{$y};
336             }
337             }
338             }
339             elsif ( defined $subref->{$x}
340             && $self->_compare( $subref->{$x}, $fref->{$x} ) )
341             {
342 24         107 $hits{$opt}{$key}{$x} = $subref->{$x};
343             }
344             }
345             else { # must be a scalar now
346 2 50 33     24 if ( defined $proc->{$x}
347             && $self->_compare( $proc->{$x}, $fref->{$x} ) )
348             {
349 2         8 $hits{$opt}{$x} = $proc->{$x};
350             }
351 2         9 last;
352             }
353             }
354             }
355             }
356             }
357              
358 2 50       18 return wantarray ? %hits : \%hits;
359             }
360              
361             sub psfind {
362 1     1 1 1000 my $self = shift;
363 1 50       6 my $filter = ref( $_[0] ) eq 'HASH' ? shift : {@_};
364 1 50       5 my $proc = $self->{processes} or return;
365 1         2 my @hits = ();
366              
367 1         3 PID: foreach my $pid ( keys %{$proc} ) {
  1         5  
368 10         14 my $proc = $proc->{$pid};
369 10         15 while ( my ( $key, $value ) = each %{$filter} ) {
  10         27  
370 5 50       10 if ( exists $proc->{$key} ) {
371 5 50       16 if ( ref $proc->{$key} eq 'HASH' ) {
    50          
372 0         0 foreach my $v ( values %{ $proc->{$key} } ) {
  0         0  
373 0 0       0 if ( $self->_compare( $v, $value ) ) {
374 0         0 push @hits, $pid;
375 0         0 next PID;
376             }
377             }
378             }
379             elsif ( $self->_compare( $proc->{$key}, $value ) ) {
380 5         11 push @hits, $pid;
381 5         12 next PID;
382             }
383             }
384             }
385             }
386              
387 1 50       6 return wantarray ? @hits : \@hits;
388             }
389              
390             sub pstop {
391 1     1 1 1468 my ( $self, $key, $count ) = @_;
392 1 50       4 unless ($key) {
393 0         0 croak 'Usage: pstop( $key => $count )';
394             }
395 1         4 my $proc = $self->{processes};
396             my @top = (
397 10         16 map { $_->[0] }
398 20         37 reverse sort { $a->[1] <=> $b->[1] }
399 1         3 map { [ $_, $proc->{$_}->{$key} ] } keys %{$proc}
  10         30  
  1         6  
400             );
401 1 50       6 if ($count) {
402 1         7 @top = @top[ 0 .. --$count ];
403             }
404 1 50       7 return wantarray ? @top : \@top;
405             }
406              
407             #
408             # private stuff
409             #
410              
411             sub _compare {
412 33     33   64 my ( $self, $x, $y ) = @_;
413              
414 33 100       339 if ( ref($y) eq 'Regexp' ) {
    100          
    100          
    100          
    50          
415 9         90 return $x =~ $y;
416             }
417             elsif ( $y =~ s/^eq:// ) {
418 1         4 return $x eq $y;
419             }
420             elsif ( $y =~ s/^ne:// ) {
421 2         27 return $x ne $y;
422             }
423             elsif ( $y =~ s/^gt:// ) {
424 3         16 return $x > $y;
425             }
426             elsif ( $y =~ s/^lt:// ) {
427 18         75 return $x < $y;
428             }
429             else {
430 0           croak ref($self) . ": bad search() / psfind() operator '$y'";
431             }
432              
433 0           return;
434             }
435              
436             1;