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