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