import torrus 1.0.9
[freeside.git] / torrus / perllib / Torrus / ReportGenerator / MonthlySrvUsage.pm
1 #  Copyright (C) 2005  Stanislav Sinyagin
2 #
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.
7 #
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.
12 #
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.
16
17 # $Id: MonthlySrvUsage.pm,v 1.1 2010-12-27 00:03:58 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
19
20 # For all service IDs available, build monthly usage figures:
21 # Average, Maximum, and Percentile (default 95th percentile)
22
23
24 package Torrus::ReportGenerator::MonthlySrvUsage;
25
26 use strict;
27 use POSIX qw(floor);
28 use Date::Parse;
29 use Math::BigFloat;
30
31 use Torrus::Log;
32 use Torrus::ReportGenerator;
33 use Torrus::ServiceID;
34
35 use base 'Torrus::ReportGenerator';
36
37 sub isMonthly
38 {
39     return 1;
40 }
41
42 sub usesSrvExport
43 {
44     return 1;
45 }
46
47
48 sub generate
49 {
50     my $self = shift;
51
52     my $percentile = $self->{'options'}->{'Percentile'};
53     if( not defined( $percentile ) )
54     {
55         $percentile = 95;
56     }
57
58     my $step = $self->{'options'}->{'Step'};
59     if( not defined( $step ) )
60     {
61         $step = 300;
62     }
63
64     my $srvIDParams = new Torrus::ServiceID();
65     
66     my $srvIDs = $self->{'srvexport'}->getServiceIDs();
67     foreach my $serviceid ( @{$srvIDs} )
68     {
69         &Torrus::DB::checkInterrupted();
70         
71         my $data = $self->{'srvexport'}->getIntervalData
72             ( $self->{'StartDate'}, $self->{'EndDate'}, $serviceid );
73
74         &Torrus::DB::checkInterrupted();
75
76         next if scalar( @{$data} ) == 0;
77         Debug('MonthlySrvUsage: Generating report for ' . $serviceid);
78
79         my $params = $srvIDParams->getParams( $serviceid );
80         
81         my @aligned = ();
82         $#aligned = floor( $self->{'RangeSeconds'} / $step );
83         my $nDatapoints = scalar( @aligned );
84             
85         # Fill in the aligned array. For each interval by modulo(step),
86         # we take the maximum value from the available data
87
88         my $maxVal = 0;
89         
90         foreach my $row ( @{$data} )
91         {
92             my $rowtime = str2time( $row->{'srv_date'} . 'T' .
93                                     $row->{'srv_time'} );
94             my $pos = floor( ($rowtime - $self->{'StartUnixTime'}) / $step );
95             my $value = Math::BigFloat->new( $row->{'value'} );
96             if( $value->is_nan() )
97             {
98                 $value->bzero();
99                 $row->{'value'} = 0;
100             }
101             
102             if( ( not defined( $aligned[$pos] ) ) or
103                 $aligned[$pos] < $value )
104             {
105                 $aligned[$pos] = $value;
106                 if( $value > $maxVal )
107                 {
108                     $maxVal = $value;
109                 }
110             }
111         }
112
113         &Torrus::DB::checkInterrupted();
114
115         # Set undefined values to zero and calculate the average
116
117         my $sum = Math::BigFloat->new(0);
118         my $unavailCount = 0;
119         foreach my $pos ( 0 .. $#aligned )
120         {
121             if( not defined( $aligned[$pos] ) )
122             {
123                 $aligned[$pos] = 0;
124                 $unavailCount++;
125             }
126             else
127             {
128                 $sum += $aligned[$pos];
129             }
130         }
131
132         &Torrus::DB::checkInterrupted();
133
134         my $avgVal = $sum / $nDatapoints;
135
136         # Calculate the percentile
137
138         my @sorted = sort {$a <=> $b} @aligned;
139         my $pcPos = floor( $nDatapoints * $percentile / 100 );
140         my $pcVal = $sorted[$pcPos];
141
142         # Calculate the total volume if it's a counter
143         my $volume = Math::BigFloat->new(0);
144         my $volumeDefined = 0;
145         if( not defined( $params->{'dstype'} ) or
146             $params->{'dstype'} =~ /^COUNTER/o )
147         {
148             $volumeDefined = 1;
149             foreach my $row ( @{$data} )
150             {
151                 $volume += $row->{'value'} * $row->{'intvl'};
152             }
153         }
154
155         # Adjust units and scale
156
157         my $usageUnits = '';
158         my $volumeUnits = '';
159         if( not defined( $params->{'units'} ) or
160             $params->{'units'} eq 'bytes' )
161         {
162             # Adjust bytes into megabit per second
163             $usageUnits = 'Mbps';
164             $maxVal *= 8e-6;
165             $avgVal *= 8e-6;
166             $pcVal  *= 8e-6;
167
168             # Adjust volume bytes into megabytes
169             $volumeUnits = 'GB';
170             $volume /= 1073741824;
171         }
172         
173         $self->{'backend'}->addField( $self->{'reportId'}, {
174             'name'      => 'MAX',
175             'serviceid' => $serviceid,
176             'value'     => $maxVal,
177             'units'     => $usageUnits });
178         
179         $self->{'backend'}->addField( $self->{'reportId'}, {
180             'name'      => 'AVG',
181             'serviceid' => $serviceid,
182             'value'     => $avgVal,
183             'units'     => $usageUnits });
184                                       
185         $self->{'backend'}->addField( $self->{'reportId'}, {
186             'name'      => sprintf('%s%s', $percentile, 'TH_PERCENTILE'),
187             'serviceid' => $serviceid,
188             'value'     => $pcVal,
189             'units'     => $usageUnits });
190         
191         $self->{'backend'}->addField( $self->{'reportId'}, {
192             'name'      => 'UNAVAIL',
193             'serviceid' => $serviceid,
194             'value'     => ($unavailCount*100)/$nDatapoints,
195             'units'     => '%' });
196
197         if( $volumeDefined )
198         {
199             $self->{'backend'}->addField( $self->{'reportId'}, {
200                 'name'      => 'VOLUME',
201                 'serviceid' => $serviceid,
202                 'value'     => $volume,
203                 'units'     => $volumeUnits });
204         }
205     }
206
207     &Torrus::DB::checkInterrupted();
208
209     $self->{'backend'}->finalize( $self->{'reportId'} );
210 }
211
212
213
214 1;
215
216
217 # Local Variables:
218 # mode: perl
219 # indent-tabs-mode: nil
220 # perl-indent-level: 4
221 # End: