File Coverage

blib/lib/Linux/Info/NetStats.pm
Criterion Covered Total %
statement 71 87 81.6
branch 13 26 50.0
condition 3 9 33.3
subroutine 11 12 91.6
pod 5 5 100.0
total 103 139 74.1


line stmt bran cond sub pod time code
1             package Linux::Info::NetStats;
2 1     1   6 use strict;
  1         2  
  1         24  
3 1     1   4 use warnings;
  1         2  
  1         26  
4 1     1   4 use Carp qw(croak);
  1         2  
  1         50  
5 1     1   419 use Time::HiRes 1.9725;
  1         1005  
  1         4  
6 1     1   411 use YAML::XS 0.41;
  1         1963  
  1         763  
7             our $VERSION = '1.3'; # VERSION
8              
9             =head1 NAME
10              
11             Linux::Info::NetStats - Collect linux net statistics.
12              
13             =head1 SYNOPSIS
14              
15             use Linux::Info::NetStats;
16              
17             my $lxs = Linux::Info::NetStats->new;
18             $lxs->init;
19             sleep 1;
20             my $stat = $lxs->get;
21              
22             Or
23              
24             my $lxs = Linux::Info::NetStats->new(initfile => $file);
25             $lxs->init;
26             my $stat = $lxs->get;
27              
28             =head1 DESCRIPTION
29              
30             Linux::Info::NetStats gathers net statistics from the virtual F filesystem (procfs).
31              
32             For more information read the documentation of the front-end module L.
33              
34             =head1 NET STATISTICS
35              
36             Generated by F.
37              
38             rxbyt - Number of bytes received per second.
39             rxpcks - Number of packets received per second.
40             rxerrs - Number of errors that happend while received packets per second.
41             rxdrop - Number of packets that were dropped per second.
42             rxfifo - Number of FIFO overruns that happend on received packets per second.
43             rxframe - Number of carrier errors that happend on received packets per second.
44             rxcompr - Number of compressed packets received per second.
45             rxmulti - Number of multicast packets received per second.
46             txbyt - Number of bytes transmitted per second.
47             txpcks - Number of packets transmitted per second.
48             txerrs - Number of errors that happend while transmitting packets per second.
49             txdrop - Number of packets that were dropped per second.
50             txfifo - Number of FIFO overruns that happend on transmitted packets per second.
51             txcolls - Number of collisions that were detected per second.
52             txcarr - Number of carrier errors that happend on transmitted packets per second.
53             txcompr - Number of compressed packets transmitted per second.
54             ttpcks - Number of total packets (received + transmitted) per second.
55             ttbyt - Number of total bytes (received + transmitted) per second.
56              
57             =head1 METHODS
58              
59             =head2 new()
60              
61             Call C to create a new object.
62              
63             my $lxs = Linux::Info::NetStats->new;
64              
65             Maybe you want to store/load the initial statistics to/from a file:
66              
67             my $lxs = Linux::Info::NetStats->new(initfile => '/tmp/netstats.yml');
68              
69             If you set C it's not necessary to call sleep before C.
70              
71             It's also possible to set the path to the proc filesystem.
72              
73             Linux::Info::NetStats->new(
74             files => {
75             # This is the default
76             path => '/proc',
77             netdev => 'net/dev',
78             }
79             );
80              
81             =head2 init()
82              
83             Call C to initialize the statistics.
84              
85             $lxs->init;
86              
87             =head2 get()
88              
89             Call C to get the statistics. C returns the statistics as a hash reference.
90              
91             my $stat = $lxs->get;
92              
93             =head2 raw()
94              
95             The same as get_raw() but it's not necessary to call init() first.
96              
97             =head2 get_raw()
98              
99             Call C to get the raw data - no deltas.
100              
101             =head1 EXPORTS
102              
103             Nothing.
104              
105             =head1 SEE ALSO
106              
107             =over
108              
109             =item *
110              
111             B
112              
113             =item *
114              
115             L
116              
117             =back
118              
119             =head1 AUTHOR
120              
121             Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
122              
123             =head1 COPYRIGHT AND LICENSE
124              
125             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior, Earfreitas@cpan.orgE
126              
127             This file is part of Linux Info project.
128              
129             Linux-Info is free software: you can redistribute it and/or modify
130             it under the terms of the GNU General Public License as published by
131             the Free Software Foundation, either version 3 of the License, or
132             (at your option) any later version.
133              
134             Linux-Info is distributed in the hope that it will be useful,
135             but WITHOUT ANY WARRANTY; without even the implied warranty of
136             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
137             GNU General Public License for more details.
138              
139             You should have received a copy of the GNU General Public License
140             along with Linux Info. If not, see .
141              
142             =cut
143              
144             sub new {
145 1     1 1 5 my $class = shift;
146 1 50       3 my $opts = ref( $_[0] ) ? shift : {@_};
147              
148 1         5 my %self = (
149             files => {
150             path => '/proc',
151             netdev => 'net/dev',
152             }
153             );
154              
155 1 50       5 if ( defined $opts->{initfile} ) {
156 0         0 $self{initfile} = $opts->{initfile};
157             }
158              
159 1         2 foreach my $file ( keys %{ $opts->{files} } ) {
  1         5  
160 0         0 $self{files}{$file} = $opts->{files}->{$file};
161             }
162              
163 1         5 return bless \%self, $class;
164             }
165              
166             sub init {
167 1     1 1 2 my $self = shift;
168              
169 1 50 33     9 if ( $self->{initfile} && -r $self->{initfile} ) {
170 0         0 $self->{init} = YAML::XS::LoadFile( $self->{initfile} );
171 0         0 $self->{time} = delete $self->{init}->{time};
172             }
173             else {
174 1         7 $self->{time} = Time::HiRes::gettimeofday();
175 1         3 $self->{init} = $self->_load;
176             }
177             }
178              
179             sub get {
180 1     1 1 3 my $self = shift;
181 1         5 my $class = ref $self;
182              
183 1 50       5 if ( !exists $self->{init} ) {
184 0         0 croak "$class: there are no initial statistics defined";
185             }
186              
187 1         4 $self->{stats} = $self->_load;
188 1         6 $self->_deltas;
189              
190 1 50       7 if ( $self->{initfile} ) {
191 0         0 $self->{init}->{time} = $self->{time};
192 0         0 YAML::XS::DumpFile( $self->{initfile}, $self->{init} );
193             }
194              
195 1         5 return $self->{stats};
196             }
197              
198             sub raw {
199 0     0 1 0 my $self = shift;
200 0         0 my $stat = $self->_load;
201              
202 0         0 return $stat;
203             }
204              
205             sub get_raw {
206 1     1 1 3 my $self = shift;
207 1         2 my %raw = %{ $self->{init} };
  1         4  
208 1         4 delete $raw{time};
209 1         4 return \%raw;
210             }
211              
212             #
213             # private stuff
214             #
215              
216             sub _load {
217 2     2   5 my $self = shift;
218 2         6 my $class = ref $self;
219 2         4 my $file = $self->{files};
220 2         4 my %stats = ();
221              
222             my $filename =
223 2 50       11 $file->{path} ? "$file->{path}/$file->{netdev}" : $file->{netdev};
224 2 50       238 open my $fh, '<', $filename
225             or croak "$class: unable to open $filename ($!)";
226              
227 2         88 while ( my $line = <$fh> ) {
228 8 100       65 next unless $line =~ /^\s*(.+?):\s*(.*)/;
229 4         45 @{ $stats{$1} }{
230 4         51 qw(
231             rxbyt rxpcks rxerrs rxdrop rxfifo rxframe rxcompr rxmulti
232             txbyt txpcks txerrs txdrop txfifo txcolls txcarr txcompr
233             )
234             } = split /\s+/, $2;
235 4         25 $stats{$1}{ttbyt} = $stats{$1}{rxbyt} + $stats{$1}{txbyt};
236 4         31 $stats{$1}{ttpcks} = $stats{$1}{rxpcks} + $stats{$1}{txpcks};
237             }
238              
239 2         22 close($fh);
240 2         16 return \%stats;
241             }
242              
243             sub _deltas {
244 1     1   3 my $self = shift;
245 1         3 my $class = ref $self;
246 1         2 my $istat = $self->{init};
247 1         3 my $lstat = $self->{stats};
248 1         14 my $time = Time::HiRes::gettimeofday();
249 1         20 my $delta = sprintf( '%.2f', $time - $self->{time} );
250 1         4 $self->{time} = $time;
251              
252 1         5 foreach my $dev ( keys %{$lstat} ) {
  1         7  
253 2 50       8 if ( !exists $istat->{$dev} ) {
254 0         0 delete $lstat->{$dev};
255 0         0 next;
256             }
257              
258 2         7 my $idev = $istat->{$dev};
259 2         5 my $ldev = $lstat->{$dev};
260              
261 2         4 while ( my ( $k, $v ) = each %{$ldev} ) {
  38         124  
262 36 50       80 if ( !defined $idev->{$k} ) {
263 0         0 croak "$class: not defined key found '$k'";
264             }
265              
266 36 50 33     186 if ( $v !~ /^\d+\z/ || $ldev->{$k} !~ /^\d+\z/ ) {
267 0         0 croak "$class: invalid value for key '$k'";
268             }
269              
270 36 50 33     111 if ( $ldev->{$k} == $idev->{$k} || $idev->{$k} > $ldev->{$k} ) {
    0          
271 36         67 $ldev->{$k} = sprintf( '%.2f', 0 );
272             }
273             elsif ( $delta > 0 ) {
274             $ldev->{$k} =
275 0         0 sprintf( '%.2f', ( $ldev->{$k} - $idev->{$k} ) / $delta );
276             }
277             else {
278 0         0 $ldev->{$k} = sprintf( '%.2f', $ldev->{$k} - $idev->{$k} );
279             }
280              
281 36         64 $idev->{$k} = $v;
282             }
283             }
284             }
285              
286             1;