File Coverage

blib/lib/Linux/Info.pm
Criterion Covered Total %
statement 62 80 77.5
branch 20 36 55.5
condition 2 8 25.0
subroutine 9 12 75.0
pod 6 6 100.0
total 99 142 69.7


line stmt bran cond sub pod time code
1             package Linux::Info;
2 14     14   753559 use strict;
  14         40  
  14         392  
3 14     14   67 use warnings;
  14         32  
  14         398  
4 14     14   73 use Carp qw(confess);
  14         29  
  14         615  
5 14     14   6349 use POSIX qw(strftime);
  14         82936  
  14         95  
6 14     14   27303 use UNIVERSAL;
  14         218  
  14         57  
7 14     14   6373 use Linux::Info::Compilation;
  14         42  
  14         206  
8              
9             our $VERSION = '1.3'; # VERSION
10              
11             =head1 NAME
12              
13             Linux::Info - API in Perl to recover information about the running Linux OS
14              
15             =head1 SYNOPSIS
16              
17             use Linux::Info;
18              
19             # you can't use sysinfo like that!
20             my $lxs = Linux::Info->new(
21             cpustats => 1,
22             procstats => 1,
23             memstats => 1,
24             pgswstats => 1,
25             netstats => 1,
26             sockstats => 1,
27             diskstats => 1,
28             diskusage => 1,
29             loadavg => 1,
30             filestats => 1,
31             processes => 1,
32             );
33              
34             sleep 1;
35             my $stat = $lxs->get;
36              
37             =head1 DESCRIPTION
38              
39             Linux::Info is a fork from L distribution.
40              
41             L is a front-end module and gather different linux system information
42             like processor workload, memory usage, network and disk statistics and a lot more. Refer the
43             documentation of the distribution modules to get more information about all possible statistics.
44              
45             =head1 MOTIVATION
46              
47             L is a great distribution (and I used it a lot), but it was built to recover
48             only Linux statistics when I was also looking for other additional information about the OS.
49              
50             Linux::Info will provide additional information not available in L, as
51             general processor information and hopefully apply patches and suggestions not implemented in the
52             original project.
53              
54             L is also more forgiving regarding compatibility with older perls interpreters,
55             modules version that it depends on and even older OS. If you find that Linux::Info is not available to your
56             old system, you should try it.
57              
58             =head1 TECHNICAL NOTE
59              
60             This distribution collects statistics by the virtual F filesystem (procfs) and is
61             developed on the default vanilla kernel. It is tested on x86 hardware with the distributions
62             RHEL, Fedora, Debian, Ubuntu, Asianux, Slackware, Mandriva and openSuSE (SLES on zSeries as
63             well but a long time ago) on kernel versions 2.4 and/or 2.6. It's possible that it doesn't
64             run on all linux distributions if some procfs features are deactivated or too much modified.
65             As example the Linux kernel 2.4 can compiled with the option C what turn
66             on or off block statistics for devices.
67              
68             =head1 VIRTUAL MACHINES
69              
70             Note that if you try to install or run C under virtual machines
71             on guest systems that some statistics are not available, such as C, C
72             and C. The reason is that not all F data are passed to the guests.
73              
74             If the installation fails then try to force the installation with
75              
76             cpan> force install Linux::Info
77              
78             and notice which tests fails, because these statistics maybe not available on the virtual machine - sorry.
79              
80             =head1 DELTAS
81              
82             The statistics for C, C, C, C, C and C
83             are deltas, for this reason it's necessary to initialize the statistics before the data can be
84             prepared by C. These statistics can be initialized with the methods C, C and
85             C. For any option that is set to 1, the statistics will be initialized by the call of
86             C or C. The call of init() re-initialize all statistics that are set to 1 or 2.
87             By the call of C the initial statistics will be updated automatically. Please refer the
88             section L to get more information about the usage of C, C, C
89             and C.
90              
91             Another exigence is to C for a while - at least for one second - before the call of C
92             if you want to get useful statistics. The statistics for C, C, C,
93             C, C and C are no deltas. If you need only one of these information
94             you don't need to sleep before the call of C.
95              
96             The method C prepares all requested statistics and returns the statistics as a
97             L object. The initial statistics will be updated.
98              
99             =head1 MANUAL PROC(5)
100              
101             The Linux Programmer's Manual
102              
103             L
104              
105             If you have questions or don't understand the sense of some statistics then take a look
106             into this awesome documentation.
107              
108             =head1 OPTIONS FOR NEW INSTANCES
109              
110             During the creation of new instances of L, you can pass as parameters to the C method different statistics to
111             collect. The statistics available are those listed on L.
112              
113             You can use the L by using their respective package names in lowercase. To activate the gathering of statistics you have to set the options by the call of C or C.
114             In addition you can deactivate statistics with C.
115              
116             The options must be set with one of the following values:
117              
118             0 - deactivate statistics
119             1 - activate and init statistics
120             2 - activate statistics but don't init
121              
122             In addition it's possible to pass a hash reference with options.
123              
124             my $lxs = Linux::Info->new(
125             processes => {
126             init => 1,
127             pids => [ 1, 2, 3 ]
128             },
129             netstats => {
130             init => 1,
131             initfile => $file,
132             },
133             );
134              
135             Option C is useful if you want to store initial statistics on the filesystem.
136              
137             my $lxs = Linux::Info->new(
138             cpustats => {
139             init => 1,
140             initfile => '/tmp/cpustats.yml',
141             },
142             diskstats => {
143             init => 1,
144             initfile => '/tmp/diskstats.yml',
145             },
146             netstats => {
147             init => 1,
148             initfile => '/tmp/netstats.yml',
149             },
150             pgswstats => {
151             init => 1,
152             initfile => '/tmp/pgswstats.yml',
153             },
154             procstats => {
155             init => 1,
156             initfile => '/tmp/procstats.yml',
157             },
158             );
159              
160             Example:
161              
162             use strict;
163             use warnings;
164             use Linux::Info;
165              
166             my $lxs = Linux::Info->new(
167             pgswstats => {
168             init => 1,
169             initfile => '/tmp/pgswstats.yml'
170             }
171             );
172              
173             $lxs->get(); # without to sleep
174              
175             The initial statistics are stored to the temporary file:
176              
177             #> cat /tmp/pgswstats.yml
178             ---
179             pgfault: 397040955
180             pgmajfault: 4611
181             pgpgin: 21531693
182             pgpgout: 49511043
183             pswpin: 8
184             pswpout: 272
185             time: 1236783534.9328
186              
187             Every time you call the script the initial statistics are loaded/stored from/to the file.
188             This could be helpful if you doesn't run it as daemon and if you want to calculate the
189             average load of your system since the last call.
190              
191             To get more information about the statistics refer the different modules of the distribution.
192              
193             cpustats - Collect cpu statistics with Linux::Info::CpuStats.
194             procstats - Collect process statistics with Linux::Info::ProcStats.
195             memstats - Collect memory statistics with Linux::Info::MemStats.
196             pgswstats - Collect paging and swapping statistics with Linux::Info::PgSwStats.
197             netstats - Collect net statistics with Linux::Info::NetStats.
198             sockstats - Collect socket statistics with Linux::Info::SockStats.
199             diskstats - Collect disk statistics with Linux::Info::DiskStats.
200             diskusage - Collect the disk usage with Linux::Info::DiskUsage.
201             loadavg - Collect the load average with Linux::Info::LoadAVG.
202             filestats - Collect inode statistics with Linux::Info::FileStats.
203             processes - Collect process statistics with Linux::Info::Processes.
204              
205             The options just described don't apply to L since this module doesn't hold statistics from the OS.
206             If you try to use it C will C with an error message. In order to use L, just
207             create an instance of it directly. See L for information on that.
208              
209             =head1 METHODS
210              
211             =head2 new()
212              
213             Call C to create a new Linux::Info object. You can call C with options.
214             This options would be passed to the method C.
215              
216             Without options
217              
218             my $lxs = Linux::Info->new();
219              
220             Or with options
221              
222             my $lxs = Linux::Info->new( cpustats => 1 );
223              
224             Would do nothing
225              
226             my $lxs = Linux::Info->new( cpustats => 0 );
227              
228             It's possible to call C with a hash reference of options.
229              
230             my %options = (
231             cpustats => 1,
232             memstats => 1
233             );
234              
235             my $lxs = Linux::Info->new(\%options);
236              
237             =head2 set()
238              
239             Call C to activate or deactivate options.
240              
241             The following example would call C and initialize C
242             and delete the object of C.
243              
244             $lxs->set(
245             processes => 0, # deactivate this statistic
246             pgswstats => 1, # activate the statistic and calls new() and init() if necessary
247             netstats => 2, # activate the statistic and call new() if necessary but not init()
248             );
249              
250             It's possible to call C with a hash reference of options.
251              
252             my %options = (
253             cpustats => 2,
254             memstats => 2
255             );
256              
257             $lxs->set(\%options);
258              
259             =head2 get()
260              
261             Call C to get the collected statistics. C returns a L
262             object.
263              
264             my $lxs = Linux::Info->new(\%options);
265             sleep(1);
266             my $stat = $lxs->get();
267              
268             Or you can pass the time to sleep with the call of C.
269              
270             my $stat = $lxs->get($time_to_sleep);
271              
272             Now the statistcs are available with
273              
274             $stat->cpustats
275              
276             # or
277              
278             $stat->{cpustats}
279              
280             Take a look to the documentation of L for more information.
281              
282             =head2 init()
283              
284             The call of C initiate all activated statistics that are necessary for deltas. That could
285             be helpful if your script runs in a endless loop with a high sleep interval. Don't forget that if
286             you call C that the statistics are deltas since the last time they were initiated.
287              
288             The following example would calculate average statistics for 30 minutes:
289              
290             # initiate cpustats
291             my $lxs = Linux::Info->new( cpustats => 1 );
292              
293             while ( 1 ) {
294             sleep(1800);
295             my $stat = $lxs->get;
296             }
297              
298             If you just want a current snapshot of the system each 30 minutes and not the average
299             then the following example would be better for you:
300              
301             # do not initiate cpustats
302             my $lxs = Linux::Info->new( cpustats => 2 );
303              
304             while ( 1 ) {
305             $lxs->init; # init the statistics
306             my $stat = $lxs->get(1); # get the statistics
307             sleep(1800); # sleep until the next run
308             }
309              
310             If you want to write a simple command line utility that prints the current workload
311             to the screen then you can use something like this:
312              
313             my @order = qw(user system iowait idle nice irq softirq total);
314             printf "%-20s%8s%8s%8s%8s%8s%8s%8s%8s\n", 'time', @order;
315              
316             my $lxs = Linux::Info->new( cpustats => 1 );
317              
318             while ( 1 ){
319             my $cpu = $lxs->get(1)->cpustats;
320             my $time = $lxs->gettime;
321             printf "%-20s%8s%8s%8s%8s%8s%8s%8s%8s\n",
322             $time, @{$cpu->{cpu}}{@order};
323             }
324              
325             =head2 settime()
326              
327             Call C to define a POSIX formatted time stamp, generated with localtime().
328              
329             $lxs->settime('%Y/%m/%d %H:%M:%S');
330              
331             To get more information about the formats take a look at C of POSIX.pm
332             or the manpage C.
333              
334             =head2 gettime()
335              
336             C returns a POSIX formatted time stamp, @foo in list and $bar in scalar context.
337             If the time format isn't set then the default format "%Y-%m-%d %H:%M:%S" will be set
338             automatically. You can also set a time format with C.
339              
340             my $date_time = $lxs->gettime;
341              
342             Or
343              
344             my ($date, $time) = $lxs->gettime();
345              
346             Or
347              
348             my ($date, $time) = $lxs->gettime('%Y/%m/%d %H:%M:%S');
349              
350             =head1 EXAMPLES
351              
352             A very simple perl script could looks like this:
353              
354             use strict;
355             use warnings;
356             use Linux::Info;
357              
358             my $lxs = Linux::Info->new( cpustats => 1 );
359             sleep(1);
360             my $stat = $lxs->get;
361             my $cpu = $stat->cpustats->{cpu};
362              
363             print "Statistics for CpuStats (all)\n";
364             print " user $cpu->{user}\n";
365             print " nice $cpu->{nice}\n";
366             print " system $cpu->{system}\n";
367             print " idle $cpu->{idle}\n";
368             print " ioWait $cpu->{iowait}\n";
369             print " total $cpu->{total}\n";
370              
371             Set and get a time stamp:
372              
373             use strict;
374             use warnings;
375             use Linux::Info;
376              
377             my $lxs = Linux::Info->new();
378             $lxs->settime('%Y/%m/%d %H:%M:%S');
379             print $lxs->gettime, "\n";
380              
381             If you want to know how the data structure looks like you can use C to check it:
382              
383             use strict;
384             use warnings;
385             use Linux::Info;
386             use Data::Dumper;
387              
388             my $lxs = Linux::Info->new( cpustats => 1 );
389             sleep(1);
390             my $stat = $lxs->get;
391              
392             print Dumper($stat);
393              
394             How to get the top 5 processes with the highest cpu workload:
395              
396             use strict;
397             use warnings;
398             use Linux::Info;
399              
400             my $lxs = Linux::Info->new( processes => 1 );
401             sleep(1);
402             my $stat = $lxs->get;
403             my @top5 = $stat->pstop( ttime => 5 );
404              
405             =head1 EXPORTS
406              
407             Nothing.
408              
409             =head1 SEE ALSO
410              
411             =over
412              
413             =item *
414              
415             The L distribution, which is base of Linux::Info
416              
417             =item *
418              
419             The project website at L.
420              
421             =back
422              
423             =head1 AUTHOR
424              
425             Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
426              
427             =head1 COPYRIGHT AND LICENSE
428              
429             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
430              
431             This file is part of Linux Info project.
432              
433             Linux Info is free software: you can redistribute it and/or modify
434             it under the terms of the GNU General Public License as published by
435             the Free Software Foundation, either version 3 of the License, or
436             (at your option) any later version.
437              
438             Linux Info is distributed in the hope that it will be useful,
439             but WITHOUT ANY WARRANTY; without even the implied warranty of
440             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
441             GNU General Public License for more details.
442              
443             You should have received a copy of the GNU General Public License
444             along with Linux Info. If not, see .
445              
446             =cut
447              
448             sub new {
449 15     15 1 9729 my $class = shift;
450 15         67 my $self = bless { obj => {} }, $class;
451              
452 15         87 my @options = qw(
453             CpuStats ProcStats
454             MemStats PgSwStats NetStats
455             SockStats DiskStats DiskUsage
456             LoadAVG FileStats Processes
457             );
458              
459 15         48 foreach my $opt (@options) {
460             # backward compatibility
461 165         372 $self->{opts}->{$opt} = 0;
462 165         293 $self->{maps}->{$opt} = $opt;
463              
464             # new style
465 165         270 my $lcopt = lc($opt);
466 165         319 $self->{opts}->{$lcopt} = 0;
467 165         314 $self->{maps}->{$lcopt} = $opt;
468             }
469              
470 15 100       69 $self->set(@_) if @_;
471 13         53 return $self;
472             }
473              
474             sub set {
475 16     16 1 3051 my $self = shift;
476 16         46 my $class = ref $self;
477 16 50       310 my $args = ref( $_[0] ) eq 'HASH' ? shift : {@_};
478 16         67 my $opts = $self->{opts};
479 16         33 my $obj = $self->{obj};
480 16         41 my $maps = $self->{maps};
481              
482              
483             confess 'Linux::Info::SysInfo cannot be instantiated from Linux::Info'
484 16 100       80 if ( exists( $args->{sysinfo} ) );
485              
486 15         62 foreach my $opt ( keys( %{$args} ) ) {
  15         68  
487              
488             confess "invalid delta option '$opt'"
489 18 100       83 unless ( exists( $opts->{$opt} ) );
490              
491 17 50       296 if ( ref( $args->{$opt} ) ) {
    50          
492 0   0     0 $opts->{$opt} = delete $args->{$opt}->{init} || 1;
493             }
494             elsif ( $args->{$opt} !~ qr/^[012]\z/ ) {
495 0         0 confess "invalid value for '$opt'";
496             }
497             else {
498 17         54 $opts->{$opt} = $args->{$opt};
499             }
500              
501 17 50       83 if ( $opts->{$opt} ) {
    0          
502 17         74 my $package = $class . '::' . $maps->{$opt};
503              
504             # require module - require know which modules are loaded
505             # and doesn't load a module twice.
506 17         39 my $require = $package;
507 17         86 $require =~ s/::/\//g;
508 17         44 $require .= '.pm';
509 17         7695 require $require;
510              
511 17 100       113 if ( !$obj->{$opt} ) {
512 16 50       77 if ( ref( $args->{$opt} ) ) {
513 0         0 $obj->{$opt} = $package->new( %{ $args->{$opt} } );
  0         0  
514             }
515             else {
516 16         122 $obj->{$opt} = $package->new();
517             }
518             }
519              
520             # get initial statistics if the function init() exists
521             # and the option is set to 1
522 17 100 66     263 if ( $opts->{$opt} == 1 && UNIVERSAL::can( $package, 'init' ) ) {
523 11         49 $obj->{$opt}->init();
524             }
525              
526             }
527             elsif ( exists $obj->{$opt} ) {
528 0         0 delete $obj->{$opt};
529             }
530             }
531             }
532              
533             sub init {
534 0     0 1 0 my $self = shift;
535 0         0 my $class = ref $self;
536              
537 0         0 foreach my $opt ( keys %{ $self->{opts} } ) {
  0         0  
538 0 0 0     0 if ( $self->{opts}->{$opt} > 0
539             && UNIVERSAL::can( ref( $self->{obj}->{$opt} ), 'init' ) )
540             {
541 0         0 $self->{obj}->{$opt}->init();
542             }
543             }
544             }
545              
546             sub get {
547 13     13 1 9001797 my ( $self, $time ) = @_;
548 13 50       118 sleep $time if $time;
549 13         88 my %stat = ();
550              
551 13         51 foreach my $opt ( keys %{ $self->{opts} } ) {
  13         252  
552 286 100       749 if ( $self->{opts}->{$opt} ) {
553 16         207 $stat{$opt} = $self->{obj}->{$opt}->get();
554 16 100       89 if ( $opt eq 'netstats' ) {
555 1         11 $stat{netinfo} = $self->{obj}->{$opt}->get_raw();
556             }
557             }
558             }
559              
560 13         179 return Linux::Info::Compilation->new( \%stat );
561             }
562              
563             sub settime {
564 0     0 1   my $self = shift;
565 0 0         my $format = @_ ? shift : '%Y-%m-%d %H:%M:%S';
566 0           $self->{timeformat} = $format;
567             }
568              
569             sub gettime {
570 0     0 1   my $self = shift;
571 0 0         $self->settime(@_) unless $self->{timeformat};
572 0           my $tm = strftime( $self->{timeformat}, localtime );
573 0 0         return wantarray ? split /\s+/, $tm : $tm;
574             }
575              
576             1;