]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bgraph.pl
ebl Use a automatic rediction when launching a new job
[bacula/bacula] / gui / 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 my $bweb = new Bweb(info => $conf);
52 $bweb->connect_db();
53 my $dbh = $bweb->{dbh};
54 my $debug = $bweb->{debug};
55
56 # Job table keep use Media or Job retention, so it's quite enought
57 # for good statistics
58 # CREATE TABLE job_old (LIKE Job);
59 # INSERT INTO job_old
60 #    (SELECT * FROM Job WHERE JobId NOT IN (SELECT JobId FROM job_old) );
61 my $jobt = $conf->{stat_job_table} || 'Job';
62
63 my $graph = CGI::param('graph') || 'job_size';
64 my $legend = CGI::param('legend') || 'on' ;
65 $legend = ($legend eq 'on')?1:0;
66
67 my $arg = $bweb->get_form(qw/width height limit offset age where jobid
68                              jfilesets level status jjobnames jclients jclient_groups/);
69
70 my ($limitq, $label) = $bweb->get_limit(age   => $arg->{age},
71                                         limit => $arg->{limit},
72                                         offset=> $arg->{offset},
73                                         order => "$jobt.StartTime ASC",
74                                         );
75
76 my $statusq='';
77 if ($arg->{status} and $arg->{status} ne 'Any') {
78     $statusq = " AND $jobt.JobStatus = '$arg->{status}' ";
79 }
80     
81 my $levelq='';
82 if ($arg->{level} and $arg->{level} ne 'Any') {
83     $levelq = " AND $jobt.Level = '$arg->{level}' ";
84
85
86 my $filesetq='';
87 if ($arg->{jfilesets}) {
88     $filesetq = " AND FileSet.FileSet IN ($arg->{qfilesets}) ";
89
90
91 my $jobnameq='';
92 if ($arg->{jjobnames}) {
93     $jobnameq = " AND $jobt.Name IN ($arg->{jjobnames}) ";
94 } else {
95     $arg->{jjobnames} = 'all';  # skip warning
96
97
98 my $clientq='';
99 if ($arg->{jclients}) {
100     $clientq = " AND Client.Name IN ($arg->{jclients}) ";
101 } else {
102     $arg->{jclients} = 'all';   # skip warning
103 }
104
105 my $groupf='';                  # from clause
106 my $groupq='';                  # whre clause
107 if ($arg->{jclient_groups}) {
108     $groupf = " JOIN client_group_member ON (Client.ClientId = client_group_member.clientid) 
109                 JOIN client_group USING (client_group_id)";
110     $groupq = " AND client_group_name IN ($arg->{jclient_groups}) ";
111 }
112
113 $bweb->can_do('r_view_stat');
114 my $filter = $bweb->get_client_filter();
115
116 my $gtype = CGI::param('gtype') || 'bars';
117
118 print CGI::header('image/png');
119
120 sub get_graph
121 {
122     my (@options) = @_;
123     my $graph;
124     if ($gtype eq 'lines') {
125         use GD::Graph::lines;
126         $graph = GD::Graph::lines->new ( $arg->{width}, $arg->{height} );
127
128     } elsif ($gtype eq 'bars') {
129         use GD::Graph::bars;
130         $graph = GD::Graph::bars->new ( $arg->{width}, $arg->{height} );
131
132     } elsif ($gtype eq 'linespoints') {
133         use GD::Graph::linespoints;
134         $graph = GD::Graph::linespoints->new ( $arg->{width}, $arg->{height} );
135
136 #   this doesnt works at this time
137 #    } elsif ($gtype eq 'bars3d') {
138 #       use GD::Graph::bars3d;
139 #       $graph = GD::Graph::bars3d->new ( $arg->{width}, $arg->{height} );
140
141     } else {
142         return undef;
143     }
144
145     $graph->set('x_label' => 'Time',
146                 'x_number_format' => sub { strftime('%D', localtime($_[0])) },
147                 'x_tick_number' => 1,
148                 @options,
149                 );
150
151     return $graph;
152 }
153
154 sub make_tab
155 {
156     my ($all_row) = @_;
157
158     my $i=0;
159     my $last_date=0;
160
161     my $ret = {};
162     
163     foreach my $row (@$all_row) {
164         my $label = $row->[1] . "/" . $row->[2] ; # client/backup name
165
166         $ret->{date}->[$i]   = $row->[0];       
167         $ret->{$label}->[$i] = $row->[3];
168         $i++;
169         $last_date = $row->[0];
170     }
171
172     # insert a fake element
173     foreach my $elt ( keys %{$ret}) {
174         $ret->{$elt}->[$i] =  undef;
175     }
176
177     $ret->{date}->[$i] = $last_date + 1;
178
179     my $date = $ret->{date} ;
180     delete $ret->{date};
181
182     return ($date, $ret);
183 }
184
185 sub make_tab_sum
186 {
187     my ($all_row) = @_;
188
189     my $i=0;
190     my $last_date=0;
191
192     my $ret = {};
193     
194     foreach my $row (@$all_row) {
195         $ret->{date}->[$i]   = $row->[0];       
196         $ret->{nb}->[$i] = $row->[1];
197         $i++;
198     }
199
200     return ($ret);
201 }
202
203 if ($graph eq 'job_size') {
204
205     my $query = "
206 SELECT 
207        UNIX_TIMESTAMP($jobt.StartTime)  AS starttime,
208        Client.Name                      AS clientname,
209        $jobt.Name                       AS jobname,
210        $jobt.JobBytes                   AS jobbytes
211 FROM $jobt, FileSet, Client $filter $groupf
212 WHERE $jobt.ClientId = Client.ClientId
213   AND $jobt.FileSetId = FileSet.FileSetId
214   AND $jobt.Type = 'B'
215   $clientq
216   $statusq
217   $filesetq
218   $levelq
219   $jobnameq
220   $groupq
221 $limitq
222 ";
223
224     print STDERR $query if ($debug);
225
226     my $obj = get_graph('title' => "Job Size : $arg->{jclients}/$arg->{jjobnames}",
227                         'y_label' => 'Size',
228                         'y_min_value' => 0,
229                         'y_number_format' => \&Bweb::human_size,
230                         );
231
232     my $all = $dbh->selectall_arrayref($query) ;
233
234     my ($d, $ret) = make_tab($all);
235     if ($legend) {
236         $obj->set_legend(keys %$ret);
237     }
238     print $obj->plot([$d, values %$ret])->png;
239 }
240
241 if ($graph eq 'job_file') {
242
243     my $query = "
244 SELECT 
245        UNIX_TIMESTAMP($jobt.StartTime)  AS starttime,
246        Client.Name                      AS clientname,
247        $jobt.Name                       AS jobname,
248        $jobt.JobFiles                   AS jobfiles
249 FROM $jobt, FileSet, Client $filter $groupf
250 WHERE $jobt.ClientId = Client.ClientId
251   AND $jobt.FileSetId = FileSet.FileSetId
252   AND $jobt.Type = 'B'
253   $clientq
254   $statusq
255   $filesetq
256   $levelq
257   $jobnameq
258   $groupq
259 $limitq
260 ";
261
262     print STDERR $query if ($debug);
263
264     my $obj = get_graph('title' => "Job Files : $arg->{jclients}/$arg->{jjobnames}",
265                         'y_label' => 'Number Files',
266                         'y_min_value' => 0,
267                         );
268
269     my $all = $dbh->selectall_arrayref($query) ;
270
271     my ($d, $ret) = make_tab($all);
272     if ($legend) {
273         $obj->set_legend(keys %$ret);
274     }
275     print $obj->plot([$d, values %$ret])->png;
276 }
277
278 # it works only with postgresql at this time
279 # we dont use $jobt because we use File, so job is in Job table
280 elsif ($graph eq 'file_histo' and $arg->{where}) {
281     
282     my $dir  = $dbh->quote(dirname($arg->{where}) . '/');
283     my $file = $dbh->quote(basename($arg->{where}));
284
285     my $query = "
286 SELECT UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
287        Client.Name                      AS client,
288        Job.Name                         AS jobname,
289        base64_decode_lstat(8,LStat)     AS lstat
290
291 FROM Job, FileSet, Filename, Path, File, Client $filter
292 WHERE Job.ClientId = Client.ClientId
293   AND Job.FileSetId = FileSet.FileSetId
294   AND Job.Type = 'B'
295   AND File.JobId = Job.JobId
296   AND File.FilenameId = Filename.FilenameId
297   AND File.PathId = Path.PathId
298   AND Path.Path = $dir
299   AND Filename.Name = $file
300   $clientq
301   $statusq
302   $filesetq
303   $levelq
304   $jobnameq
305 $limitq
306 ";
307
308     print STDERR $query if ($debug);
309
310     my $all = $dbh->selectall_arrayref($query) ;
311
312     my $obj = get_graph('title' => "File size : $arg->{where}",
313                         'y_label' => 'File size',
314                         'y_min_value' => 0,
315                         'y_min_value' => 0,
316                         'y_number_format' => \&Bweb::human_size,
317                         );
318
319
320     my ($d, $ret) = make_tab($all);
321     if ($legend) {
322         $obj->set_legend(keys %$ret);
323     }
324     print $obj->plot([$d, values %$ret])->png;
325 }
326
327 # it works only with postgresql at this time
328 # TODO: use brestore_missing_path
329 elsif ($graph eq 'rep_histo' and $arg->{where}) {
330     
331     my $dir  = $arg->{where};
332     $dir .= '/' if ($dir !~ m!/$!);
333     $dir = $dbh->quote($dir);
334
335     my $query = "
336 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
337        Client.Name                   AS client,
338        Job.Name                      AS jobname,
339        brestore_pathvisibility.size  AS size
340
341 FROM Job, Client $filter, FileSet, Path, brestore_pathvisibility
342 WHERE Job.ClientId = Client.ClientId
343   AND Job.FileSetId = FileSet.FileSetId
344   AND Job.Type = 'B'
345   AND Job.JobId = brestore_pathvisibility.JobId
346   AND Path.PathId = brestore_pathvisibility.PathId
347   AND Path.Path = $dir
348   $clientq
349   $statusq
350   $filesetq
351   $levelq
352   $jobnameq
353 $limitq
354 ";
355
356     print STDERR $query if ($debug);
357
358     my $all = $dbh->selectall_arrayref($query) ;
359
360     my $obj = get_graph('title' => "Directory size : $arg->{where}",
361                         'y_label' => 'Directory size',
362                         'y_min_value' => 0,
363                         'y_min_value' => 0,
364                         'y_number_format' => \&Bweb::human_size,
365                         );
366
367
368     my ($d, $ret) = make_tab($all);
369     if ($legend) {
370         $obj->set_legend(keys %$ret);
371     }
372     print $obj->plot([$d, values %$ret])->png;
373 }
374
375 elsif ($graph eq 'job_rate') {
376
377     my $query = "
378 SELECT 
379        UNIX_TIMESTAMP($jobt.StartTime)  AS starttime,
380        Client.Name                      AS clientname,
381        $jobt.Name                       AS jobname,
382        $jobt.JobBytes /
383        ($bweb->{sql}->{SEC_TO_INT}(
384                           $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
385                         - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01) 
386          AS rate
387
388 FROM $jobt, FileSet, Client $filter $groupf
389 WHERE $jobt.ClientId = Client.ClientId
390   AND $jobt.FileSetId = FileSet.FileSetId
391   AND $jobt.Type = 'B'
392   $clientq
393   $statusq
394   $filesetq
395   $levelq
396   $jobnameq
397   $groupq
398 $limitq
399 ";
400
401     print STDERR $query if ($debug);
402
403     my $obj = get_graph('title' => "Job Rate : $arg->{jclients}/$arg->{jjobnames}",
404                         'y_label' => 'Rate b/s',
405                         'y_min_value' => 0,
406                         'y_number_format' => \&Bweb::human_size,
407                         );
408
409     my $all = $dbh->selectall_arrayref($query) ;
410
411     my ($d, $ret) = make_tab($all);    
412     if ($legend) {
413         $obj->set_legend(keys %$ret);
414     }
415     print $obj->plot([$d, values %$ret])->png;
416 }
417
418
419
420 elsif ($graph eq 'job_duration') {
421
422     my $query = "
423 SELECT 
424        UNIX_TIMESTAMP($jobt.StartTime)                         AS starttime,
425        Client.Name                                             AS clientname,
426        $jobt.Name                                              AS jobname,
427   $bweb->{sql}->{SEC_TO_INT}(  $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
428                              - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
429          AS duration
430 FROM $jobt, FileSet, Client $filter $groupf
431 WHERE $jobt.ClientId = Client.ClientId
432   AND $jobt.FileSetId = FileSet.FileSetId
433   AND $jobt.Type = 'B'
434   $clientq
435   $statusq
436   $filesetq
437   $levelq
438   $jobnameq
439   $groupq
440 $limitq
441 ";
442
443     print STDERR $query if ($debug);
444
445     my $obj = get_graph('title' => "Job Duration : $arg->{jclients}/$arg->{jjobnames}",
446                         'y_label' => 'Duration',
447                         'y_min_value' => 0,
448                         'y_number_format' => \&Bweb::human_sec,
449                         );
450     my $all = $dbh->selectall_arrayref($query) ;
451
452     my ($d, $ret) = make_tab($all);
453     if ($legend) {
454         $obj->set_legend(keys %$ret);
455     }
456     print $obj->plot([$d, values %$ret])->png;
457
458
459 # number of job per day/hour
460 } elsif ($graph =~ /^job_(count|sum|avg)_((p?)(day|hour|month))$/) {
461     my $t = $1;
462     my $d = uc($2);
463     my $per_t = $3;
464     my ($limit, $label) = $bweb->get_limit(age   => $arg->{age},
465                                            limit => $arg->{limit},
466                                            offset=> $arg->{offset},
467                                            groupby => "A",
468                                            order => "A",
469                                            );
470     my @arg;                    # arg for plotting
471
472     if (!$per_t) {              # much better aspect
473         #$gtype = 'lines';
474     } else {
475         push @arg, ("x_number_format" => undef,
476                     "x_min_value" => 0,
477                     );
478     }
479
480     if ($t eq 'sum' or $t eq 'avg') {
481         push @arg, ('y_number_format' => \&Bweb::human_size);
482     }
483     
484     my $stime = $bweb->{sql}->{"STARTTIME_$d"};
485     $stime =~ s/Job\./$jobt\./;
486
487     my $query = "
488 SELECT
489      " . ($per_t?"":"UNIX_TIMESTAMP") . "($stime) AS A,
490      $t(JobBytes)                  AS nb
491 FROM $jobt, FileSet, Client $filter $groupf
492 WHERE $jobt.ClientId = Client.ClientId
493   AND $jobt.FileSetId = FileSet.FileSetId
494   AND $jobt.Type = 'B'
495   $clientq
496   $statusq
497   $filesetq
498   $levelq
499   $jobnameq
500   $groupq
501 $limit
502 ";
503
504     print STDERR $query  if ($debug);
505
506     my $obj = get_graph('title' => "Job $t : $arg->{jclients}/$arg->{jjobnames}",
507                         'y_label' => $t,
508                         'y_min_value' => 0,
509                         @arg,
510                         );
511
512     my $all = $dbh->selectall_arrayref($query) ;
513 #    print STDERR Data::Dumper::Dumper($all);
514     my ($ret) = make_tab_sum($all);
515
516     print $obj->plot([$ret->{date}, $ret->{nb}])->png;    
517 }
518
519 $dbh->disconnect();