Merge remote-tracking branch 'upstream/master'
[torrus-plus.git] / src / lib / Torrus / ReportGenerator / MonthlySrvUsage.pm
blob635136360231cd12cbb716dc94dfe6f9ca1c915a
1 # Copyright (C) 2005 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id$
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # For all service IDs available, build monthly usage figures:
21 # Average, Maximum, and Percentile (default 95th percentile)
24 package Torrus::ReportGenerator::MonthlySrvUsage;
26 use strict;
27 use warnings;
29 use base 'Torrus::ReportGenerator';
31 use POSIX qw(floor);
32 use Date::Parse;
33 use Math::BigFloat;
35 use Torrus::Log;
36 use Torrus::ServiceID;
39 our $VERSION = 1.0;
41 sub isMonthly
43 return 1;
46 sub usesSrvExport
48 return 1;
52 sub generate
54 my $self = shift;
56 my $percentile = $self->{'options'}->{'Percentile'};
57 if( not defined( $percentile ) )
59 $percentile = 95;
62 my $step = $self->{'options'}->{'Step'};
63 if( not defined( $step ) )
65 $step = 300;
68 my $srvIDParams = Torrus::ServiceID->new();
70 my $srvIDs = $self->{'srvexport'}->getServiceIDs();
71 for my $serviceid ( @{$srvIDs} )
73 &Torrus::DB::checkInterrupted();
75 my $data = $self->{'srvexport'}->getIntervalData
76 ( $self->{'StartDate'}, $self->{'EndDate'}, $serviceid );
78 &Torrus::DB::checkInterrupted();
80 next if scalar( @{$data} ) == 0;
81 Debug('MonthlySrvUsage: Generating report for ' . $serviceid);
83 my $params = $srvIDParams->getParams( $serviceid );
85 my @aligned = ();
86 $#aligned = floor( $self->{'RangeSeconds'} / $step );
87 my $nDatapoints = scalar( @aligned );
89 # Fill in the aligned array. For each interval by modulo(step),
90 # we take the maximum value from the available data
92 my $maxVal = 0;
94 for my $row ( @{$data} )
96 my $rowtime = str2time( $row->{'srv_date'} . 'T' .
97 $row->{'srv_time'} );
98 my $pos = floor( ($rowtime - $self->{'StartUnixTime'}) / $step );
99 my $value = Math::BigFloat->new( $row->{'value'} );
100 if( $value->is_nan() )
102 $value->bzero();
103 $row->{'value'} = 0;
106 if( ( not defined( $aligned[$pos] ) ) or
107 $aligned[$pos] < $value )
109 $aligned[$pos] = $value;
110 if( $value > $maxVal )
112 $maxVal = $value;
117 &Torrus::DB::checkInterrupted();
119 # Set undefined values to zero and calculate the average
121 my $sum = Math::BigFloat->new(0);
122 my $unavailCount = 0;
123 for my $pos ( 0 .. $#aligned )
125 if( not defined( $aligned[$pos] ) )
127 $aligned[$pos] = 0;
128 $unavailCount++;
130 else
132 $sum += $aligned[$pos];
136 &Torrus::DB::checkInterrupted();
138 my $avgVal = $sum / $nDatapoints;
140 # Calculate the percentile
142 my @sorted = sort {$a <=> $b} @aligned;
143 my $pcPos = floor( $nDatapoints * $percentile / 100 );
144 my $pcVal = $sorted[$pcPos];
146 # Calculate the total volume if it's a counter
147 my $volume = Math::BigFloat->new(0);
148 my $volumeDefined = 0;
149 if( not defined( $params->{'dstype'} ) or
150 $params->{'dstype'} =~ /^COUNTER/o )
152 $volumeDefined = 1;
153 for my $row ( @{$data} )
155 $volume += $row->{'value'} * $row->{'intvl'};
159 # Adjust units and scale
161 my $usageUnits = '';
162 my $volumeUnits = '';
163 if( not defined( $params->{'units'} ) or
164 $params->{'units'} eq 'bytes' )
166 # Adjust bytes into megabit per second
167 $usageUnits = 'Mbps';
168 $maxVal *= 8e-6;
169 $avgVal *= 8e-6;
170 $pcVal *= 8e-6;
172 # Adjust volume bytes into megabytes
173 $volumeUnits = 'GB';
174 $volume /= 1073741824;
177 $self->{'backend'}->addField( $self->{'reportId'}, {
178 'name' => 'MAX',
179 'serviceid' => $serviceid,
180 'value' => $maxVal,
181 'units' => $usageUnits });
183 $self->{'backend'}->addField( $self->{'reportId'}, {
184 'name' => 'AVG',
185 'serviceid' => $serviceid,
186 'value' => $avgVal,
187 'units' => $usageUnits });
189 $self->{'backend'}->addField( $self->{'reportId'}, {
190 'name' => sprintf('%s%s', $percentile, 'TH_PERCENTILE'),
191 'serviceid' => $serviceid,
192 'value' => $pcVal,
193 'units' => $usageUnits });
195 $self->{'backend'}->addField( $self->{'reportId'}, {
196 'name' => 'UNAVAIL',
197 'serviceid' => $serviceid,
198 'value' => ($unavailCount*100)/$nDatapoints,
199 'units' => '%' });
201 if( $volumeDefined )
203 $self->{'backend'}->addField( $self->{'reportId'}, {
204 'name' => 'VOLUME',
205 'serviceid' => $serviceid,
206 'value' => $volume,
207 'units' => $volumeUnits });
211 &Torrus::DB::checkInterrupted();
213 $self->{'backend'}->finalize( $self->{'reportId'} );
221 # Local Variables:
222 # mode: perl
223 # indent-tabs-mode: nil
224 # perl-indent-level: 4
225 # End: