]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/bweb/cgi/bgraph.pl
c7540c7af93b3ca3afe629b9eb9387366331b8e0
[bacula/bacula] / gui / bweb / bweb / cgi / bgraph.pl
1 #!/usr/bin/perl -w
2 use strict;
3
4 =head1 LICENSE
5
6    Bweb - A Bacula web interface
7    Bacula® - The Network Backup Solution
8
9    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
10
11    The main author of Bweb is Eric Bollengier.
12    The main author of Bacula is Kern Sibbald, with contributions from
13    many others, a complete list can be found in the file AUTHORS.
14
15    This program is Free Software; you can redistribute it and/or
16    modify it under the terms of version two of the GNU General Public
17    License as published by the Free Software Foundation plus additions
18    that are listed in the file LICENSE.
19
20    This program is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28    02110-1301, USA.
29
30    Bacula® is a registered trademark of John Walker.
31    The licensor of Bacula is the Free Software Foundation Europe
32    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
33    Switzerland, email:ftf@fsfeurope.org.
34
35 =head1 VERSION
36
37     $Id$
38
39 =cut
40
41 use Bweb;
42
43 use Data::Dumper;
44 use CGI;
45
46 use POSIX qw/strftime/;
47 use File::Basename qw/basename dirname/;
48
49 my $conf = new Bweb::Config(config_file => $Bweb::config_file);
50 $conf->load();
51
52 my $bweb = new Bweb(info => $conf);
53 $bweb->connect_db();
54 my $dbh = $bweb->{dbh};
55 my $debug = $bweb->{debug};
56
57 my $graph = CGI::param('graph') || 'job_size';
58 my $legend = CGI::param('legend') || 'on' ;
59 $legend = ($legend eq 'on')?1:0;
60
61 my $arg = $bweb->get_form(qw/width height limit offset age where jobid
62                              jfilesets level status jjobnames jclients/);
63
64 my ($limitq, $label) = $bweb->get_limit(age   => $arg->{age},
65                                         limit => $arg->{limit},
66                                         offset=> $arg->{offset},
67                                         order => 'Job.StartTime ASC',
68                                         );
69
70 my $statusq='';
71 if ($arg->{status} and $arg->{status} ne 'Any') {
72     $statusq = " AND Job.JobStatus = '$arg->{status}' ";
73 }
74     
75 my $levelq='';
76 if ($arg->{level} and $arg->{level} ne 'Any') {
77     $levelq = " AND Job.Level = '$arg->{level}' ";
78
79
80 my $filesetq='';
81 if ($arg->{jfilesets}) {
82     $filesetq = " AND FileSet.FileSet IN ($arg->{qfilesets}) ";
83
84
85 my $jobnameq='';
86 if ($arg->{jjobnames}) {
87     $jobnameq = " AND Job.Name IN ($arg->{jjobnames}) ";
88 } else {
89     $arg->{jjobnames} = 'all';  # skip warning
90
91
92 my $clientq='';
93 if ($arg->{jclients}) {
94     $clientq = " AND Client.Name IN ($arg->{jclients}) ";
95 } else {
96     $arg->{jclients} = 'all';   # skip warning
97 }
98
99 my $gtype = CGI::param('gtype') || 'bars';
100
101 print CGI::header('image/png');
102
103 sub get_graph
104 {
105     my (@options) = @_;
106     my $graph;
107     if ($gtype eq 'lines') {
108         use GD::Graph::lines;
109         $graph = GD::Graph::lines->new ( $arg->{width}, $arg->{height} );
110
111     } elsif ($gtype eq 'bars') {
112         use GD::Graph::bars;
113         $graph = GD::Graph::bars->new ( $arg->{width}, $arg->{height} );
114
115     } elsif ($gtype eq 'linespoints') {
116         use GD::Graph::linespoints;
117         $graph = GD::Graph::linespoints->new ( $arg->{width}, $arg->{height} );
118
119 #   this doesnt works at this time
120 #    } elsif ($gtype eq 'bars3d') {
121 #       use GD::Graph::bars3d;
122 #       $graph = GD::Graph::bars3d->new ( $arg->{width}, $arg->{height} );
123
124     } else {
125         return undef;
126     }
127
128     $graph->set('x_label' => 'Time',
129                 'x_number_format' => sub { strftime('%D', localtime($_[0])) },
130                 'x_tick_number' => 1,
131                 @options,
132                 );
133
134     return $graph;
135 }
136
137 sub make_tab
138 {
139     my ($all_row) = @_;
140
141     my $i=0;
142     my $last_date=0;
143
144     my $ret = {};
145     
146     foreach my $row (@$all_row) {
147         my $label = $row->[1] . "/" . $row->[2] ; # client/backup name
148
149         $ret->{date}->[$i]   = $row->[0];       
150         $ret->{$label}->[$i] = $row->[3];
151         $i++;
152         $last_date = $row->[0];
153     }
154
155     # insert a fake element
156     foreach my $elt ( keys %{$ret}) {
157         $ret->{$elt}->[$i] =  undef;
158     }
159
160     $ret->{date}->[$i] = $last_date + 1;
161
162     my $date = $ret->{date} ;
163     delete $ret->{date};
164
165     return ($date, $ret);
166 }
167
168 sub make_tab_sum
169 {
170     my ($all_row) = @_;
171
172     my $i=0;
173     my $last_date=0;
174
175     my $ret = {};
176     
177     foreach my $row (@$all_row) {
178         $ret->{date}->[$i]   = $row->[0];       
179         $ret->{nb}->[$i] = $row->[1];
180         $i++;
181     }
182
183     return ($ret);
184 }
185
186 if ($graph eq 'job_size') {
187
188     my $query = "
189 SELECT 
190        UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
191        Client.Name                      AS clientname,
192        Job.Name                         AS jobname,
193        Job.JobBytes                     AS jobbytes
194 FROM Job, Client, FileSet
195 WHERE Job.ClientId = Client.ClientId
196   AND Job.FileSetId = FileSet.FileSetId
197   AND Job.Type = 'B'
198   $clientq
199   $statusq
200   $filesetq
201   $levelq
202   $jobnameq
203 $limitq
204 ";
205
206     print STDERR $query if ($debug);
207
208     my $obj = get_graph('title' => "Job Size : $arg->{jclients}/$arg->{jjobnames}",
209                         'y_label' => 'Size',
210                         'y_min_value' => 0,
211                         'y_number_format' => \&Bweb::human_size,
212                         );
213
214     my $all = $dbh->selectall_arrayref($query) ;
215
216     my ($d, $ret) = make_tab($all);
217     if ($legend) {
218         $obj->set_legend(keys %$ret);
219     }
220     print $obj->plot([$d, values %$ret])->png;
221 }
222
223 if ($graph eq 'job_file') {
224
225     my $query = "
226 SELECT 
227        UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
228        Client.Name                      AS clientname,
229        Job.Name                         AS jobname,
230        Job.JobFiles                     AS jobfiles
231 FROM Job, Client, FileSet
232 WHERE Job.ClientId = Client.ClientId
233   AND Job.FileSetId = FileSet.FileSetId
234   AND Job.Type = 'B'
235   $clientq
236   $statusq
237   $filesetq
238   $levelq
239   $jobnameq
240 $limitq
241 ";
242
243     print STDERR $query if ($debug);
244
245     my $obj = get_graph('title' => "Job Files : $arg->{jclients}/$arg->{jjobnames}",
246                         'y_label' => 'Number Files',
247                         'y_min_value' => 0,
248                         );
249
250     my $all = $dbh->selectall_arrayref($query) ;
251
252     my ($d, $ret) = make_tab($all);
253     if ($legend) {
254         $obj->set_legend(keys %$ret);
255     }
256     print $obj->plot([$d, values %$ret])->png;
257 }
258
259 # it works only with postgresql at this time
260 elsif ($graph eq 'file_histo' and $arg->{where}) {
261     
262     my $dir  = $dbh->quote(dirname($arg->{where}) . '/');
263     my $file = $dbh->quote(basename($arg->{where}));
264
265     my $query = "
266 SELECT UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
267        Client.Name                      AS client,
268        Job.Name                         AS jobname,
269        base64_decode_lstat(8,LStat)     AS lstat
270
271 FROM Job, Client, FileSet, Filename, Path, File
272 WHERE Job.ClientId = Client.ClientId
273   AND Job.FileSetId = FileSet.FileSetId
274   AND Job.Type = 'B'
275   AND File.JobId = Job.JobId
276   AND File.FilenameId = Filename.FilenameId
277   AND File.PathId = Path.PathId
278   AND Path.Path = $dir
279   AND Filename.Name = $file
280   $clientq
281   $statusq
282   $filesetq
283   $levelq
284   $jobnameq
285 $limitq
286 ";
287
288     print STDERR $query if ($debug);
289
290     my $all = $dbh->selectall_arrayref($query) ;
291
292     my $obj = get_graph('title' => "File size : $arg->{where}",
293                         'y_label' => 'File size',
294                         'y_min_value' => 0,
295                         'y_min_value' => 0,
296                         'y_number_format' => \&Bweb::human_size,
297                         );
298
299
300     my ($d, $ret) = make_tab($all);
301     if ($legend) {
302         $obj->set_legend(keys %$ret);
303     }
304     print $obj->plot([$d, values %$ret])->png;
305 }
306
307 # it works only with postgresql at this time
308 # TODO: use brestore_missing_path
309 elsif ($graph eq 'rep_histo' and $arg->{where}) {
310     
311     my $dir  = $arg->{where};
312     $dir .= '/' if ($dir !~ m!/$!);
313     $dir = $dbh->quote($dir);
314
315     my $query = "
316 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
317        Client.Name                   AS client,
318        Job.Name                      AS jobname,
319        brestore_pathvisibility.size  AS size
320
321 FROM Job, Client, FileSet, Path, brestore_pathvisibility
322 WHERE Job.ClientId = Client.ClientId
323   AND Job.FileSetId = FileSet.FileSetId
324   AND Job.Type = 'B'
325   AND Job.JobId = brestore_pathvisibility.JobId
326   AND Path.PathId = brestore_pathvisibility.PathId
327   AND Path.Path = $dir
328   $clientq
329   $statusq
330   $filesetq
331   $levelq
332   $jobnameq
333 $limitq
334 ";
335
336     print STDERR $query if ($debug);
337
338     my $all = $dbh->selectall_arrayref($query) ;
339
340     my $obj = get_graph('title' => "Directory size : $arg->{where}",
341                         'y_label' => 'Directory size',
342                         'y_min_value' => 0,
343                         'y_min_value' => 0,
344                         'y_number_format' => \&Bweb::human_size,
345                         );
346
347
348     my ($d, $ret) = make_tab($all);
349     if ($legend) {
350         $obj->set_legend(keys %$ret);
351     }
352     print $obj->plot([$d, values %$ret])->png;
353 }
354
355 elsif ($graph eq 'job_rate') {
356
357     my $query = "
358 SELECT 
359        UNIX_TIMESTAMP(Job.StartTime)                          AS starttime,
360        Client.Name                      AS clientname,
361        Job.Name                         AS jobname,
362        Job.JobBytes /
363        ($bweb->{sql}->{SEC_TO_INT}(
364                           $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
365                         - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01) 
366          AS rate
367
368 FROM Job, Client, FileSet
369 WHERE Job.ClientId = Client.ClientId
370   AND Job.FileSetId = FileSet.FileSetId
371   AND Job.Type = 'B'
372   $clientq
373   $statusq
374   $filesetq
375   $levelq
376   $jobnameq
377 $limitq
378 ";
379
380     print STDERR $query if ($debug);
381
382     my $obj = get_graph('title' => "Job Rate : $arg->{jclients}/$arg->{jjobnames}",
383                         'y_label' => 'Rate b/s',
384                         'y_min_value' => 0,
385                         'y_number_format' => \&Bweb::human_size,
386                         );
387
388     my $all = $dbh->selectall_arrayref($query) ;
389
390     my ($d, $ret) = make_tab($all);    
391     if ($legend) {
392         $obj->set_legend(keys %$ret);
393     }
394     print $obj->plot([$d, values %$ret])->png;
395 }
396
397
398
399 elsif ($graph eq 'job_duration') {
400
401     my $query = "
402 SELECT 
403        UNIX_TIMESTAMP(Job.StartTime)                           AS starttime,
404        Client.Name                                             AS clientname,
405        Job.Name                                                AS jobname,
406   $bweb->{sql}->{SEC_TO_INT}(  $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
407                              - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
408          AS duration
409 FROM Job, Client, FileSet
410 WHERE Job.ClientId = Client.ClientId
411   AND Job.FileSetId = FileSet.FileSetId
412   AND Job.Type = 'B'
413   $clientq
414   $statusq
415   $filesetq
416   $levelq
417   $jobnameq
418 $limitq
419 ";
420
421     print STDERR $query if ($debug);
422
423     my $obj = get_graph('title' => "Job Duration : $arg->{jclients}/$arg->{jjobnames}",
424                         'y_label' => 'Duration',
425                         'y_min_value' => 0,
426                         'y_number_format' => \&Bweb::human_sec,
427                         );
428     my $all = $dbh->selectall_arrayref($query) ;
429
430     my ($d, $ret) = make_tab($all);
431     if ($legend) {
432         $obj->set_legend(keys %$ret);
433     }
434     print $obj->plot([$d, values %$ret])->png;
435
436
437 # number of job per day/hour
438 } elsif ($graph =~ /^job_(count|sum|avg)_((p?)(day|hour|month))$/) {
439     my $t = $1;
440     my $d = uc($2);
441     my $per_t = $3;
442     my ($limit, $label) = $bweb->get_limit(age   => $arg->{age},
443                                            limit => $arg->{limit},
444                                            offset=> $arg->{offset},
445                                            groupby => "A",
446                                            );
447     my @arg;                    # arg for plotting
448
449     if (!$per_t) {              # much better aspect
450         #$gtype = 'lines';
451     } else {
452         push @arg, ("x_number_format" => undef,
453                     "x_min_value" => 0,
454                     );
455     }
456
457     if ($t eq 'sum' or $t eq 'avg') {
458         push @arg, ('y_number_format' => \&Bweb::human_size);
459     }
460
461     my $query = "
462 SELECT
463      " . ($per_t?"":"UNIX_TIMESTAMP") . "(" . $bweb->{sql}->{"STARTTIME_$d"} . ") AS A,
464      $t(JobBytes)                  AS nb
465 FROM Job, Client, FileSet
466 WHERE Job.ClientId = Client.ClientId
467   AND Job.FileSetId = FileSet.FileSetId
468   AND Job.Type = 'B'
469   $clientq
470   $statusq
471   $filesetq
472   $levelq
473   $jobnameq
474 $limit
475 ";
476
477     print STDERR $query  if ($debug);
478
479     my $obj = get_graph('title' => "Job $t : $arg->{jclients}/$arg->{jjobnames}",
480                         'y_label' => $t,
481                         'y_min_value' => 0,
482                         @arg,
483                         );
484
485     my $all = $dbh->selectall_arrayref($query) ;
486     my ($ret) = make_tab_sum($all);
487
488     print $obj->plot([$ret->{date}, $ret->{nb}])->png;    
489 }
490