6 Bweb - A Bacula web interface
7 Bacula® - The Network Backup Solution
9 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
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.
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.
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.
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
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.
46 use POSIX qw/strftime/;
47 use File::Basename qw/basename dirname/;
49 my $conf = new Bweb::Config(config_file => $Bweb::config_file);
51 my $bweb = new Bweb(info => $conf);
53 my $dbh = $bweb->{dbh};
54 my $debug = $bweb->{debug};
56 # Job table keep use Media or Job retention, so it's quite enought
58 # CREATE TABLE job_old (LIKE Job);
60 # (SELECT * FROM Job WHERE JobId NOT IN (SELECT JobId FROM job_old) );
61 my $jobt = $conf->{stat_job_table} || 'Job';
63 my $graph = CGI::param('graph') || 'job_size';
64 my $legend = CGI::param('legend') || 'on' ;
65 $legend = ($legend eq 'on')?1:0;
67 my $arg = $bweb->get_form(qw/width height limit offset age where jobid
68 jfilesets level status jjobnames jclients/);
70 my ($limitq, $label) = $bweb->get_limit(age => $arg->{age},
71 limit => $arg->{limit},
72 offset=> $arg->{offset},
73 order => "$jobt.StartTime ASC",
77 if ($arg->{status} and $arg->{status} ne 'Any') {
78 $statusq = " AND $jobt.JobStatus = '$arg->{status}' ";
82 if ($arg->{level} and $arg->{level} ne 'Any') {
83 $levelq = " AND $jobt.Level = '$arg->{level}' ";
87 if ($arg->{jfilesets}) {
88 $filesetq = " AND FileSet.FileSet IN ($arg->{qfilesets}) ";
92 if ($arg->{jjobnames}) {
93 $jobnameq = " AND $jobt.Name IN ($arg->{jjobnames}) ";
95 $arg->{jjobnames} = 'all'; # skip warning
99 if ($arg->{jclients}) {
100 $clientq = " AND Client.Name IN ($arg->{jclients}) ";
102 $arg->{jclients} = 'all'; # skip warning
105 my $gtype = CGI::param('gtype') || 'bars';
107 print CGI::header('image/png');
113 if ($gtype eq 'lines') {
114 use GD::Graph::lines;
115 $graph = GD::Graph::lines->new ( $arg->{width}, $arg->{height} );
117 } elsif ($gtype eq 'bars') {
119 $graph = GD::Graph::bars->new ( $arg->{width}, $arg->{height} );
121 } elsif ($gtype eq 'linespoints') {
122 use GD::Graph::linespoints;
123 $graph = GD::Graph::linespoints->new ( $arg->{width}, $arg->{height} );
125 # this doesnt works at this time
126 # } elsif ($gtype eq 'bars3d') {
127 # use GD::Graph::bars3d;
128 # $graph = GD::Graph::bars3d->new ( $arg->{width}, $arg->{height} );
134 $graph->set('x_label' => 'Time',
135 'x_number_format' => sub { strftime('%D', localtime($_[0])) },
136 'x_tick_number' => 1,
152 foreach my $row (@$all_row) {
153 my $label = $row->[1] . "/" . $row->[2] ; # client/backup name
155 $ret->{date}->[$i] = $row->[0];
156 $ret->{$label}->[$i] = $row->[3];
158 $last_date = $row->[0];
161 # insert a fake element
162 foreach my $elt ( keys %{$ret}) {
163 $ret->{$elt}->[$i] = undef;
166 $ret->{date}->[$i] = $last_date + 1;
168 my $date = $ret->{date} ;
171 return ($date, $ret);
183 foreach my $row (@$all_row) {
184 $ret->{date}->[$i] = $row->[0];
185 $ret->{nb}->[$i] = $row->[1];
192 if ($graph eq 'job_size') {
196 UNIX_TIMESTAMP($jobt.StartTime) AS starttime,
197 Client.Name AS clientname,
198 $jobt.Name AS jobname,
199 $jobt.JobBytes AS jobbytes
200 FROM $jobt, Client, FileSet
201 WHERE $jobt.ClientId = Client.ClientId
202 AND $jobt.FileSetId = FileSet.FileSetId
212 print STDERR $query if ($debug);
214 my $obj = get_graph('title' => "Job Size : $arg->{jclients}/$arg->{jjobnames}",
217 'y_number_format' => \&Bweb::human_size,
220 my $all = $dbh->selectall_arrayref($query) ;
222 my ($d, $ret) = make_tab($all);
224 $obj->set_legend(keys %$ret);
226 print $obj->plot([$d, values %$ret])->png;
229 if ($graph eq 'job_file') {
233 UNIX_TIMESTAMP($jobt.StartTime) AS starttime,
234 Client.Name AS clientname,
235 $jobt.Name AS jobname,
236 $jobt.JobFiles AS jobfiles
237 FROM $jobt, Client, FileSet
238 WHERE $jobt.ClientId = Client.ClientId
239 AND $jobt.FileSetId = FileSet.FileSetId
249 print STDERR $query if ($debug);
251 my $obj = get_graph('title' => "Job Files : $arg->{jclients}/$arg->{jjobnames}",
252 'y_label' => 'Number Files',
256 my $all = $dbh->selectall_arrayref($query) ;
258 my ($d, $ret) = make_tab($all);
260 $obj->set_legend(keys %$ret);
262 print $obj->plot([$d, values %$ret])->png;
265 # it works only with postgresql at this time
266 # we dont use $jobt because we use File, so job is in Job table
267 elsif ($graph eq 'file_histo' and $arg->{where}) {
269 my $dir = $dbh->quote(dirname($arg->{where}) . '/');
270 my $file = $dbh->quote(basename($arg->{where}));
273 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
274 Client.Name AS client,
276 base64_decode_lstat(8,LStat) AS lstat
278 FROM Job, Client, FileSet, Filename, Path, File
279 WHERE Job.ClientId = Client.ClientId
280 AND Job.FileSetId = FileSet.FileSetId
282 AND File.JobId = Job.JobId
283 AND File.FilenameId = Filename.FilenameId
284 AND File.PathId = Path.PathId
286 AND Filename.Name = $file
295 print STDERR $query if ($debug);
297 my $all = $dbh->selectall_arrayref($query) ;
299 my $obj = get_graph('title' => "File size : $arg->{where}",
300 'y_label' => 'File size',
303 'y_number_format' => \&Bweb::human_size,
307 my ($d, $ret) = make_tab($all);
309 $obj->set_legend(keys %$ret);
311 print $obj->plot([$d, values %$ret])->png;
314 # it works only with postgresql at this time
315 # TODO: use brestore_missing_path
316 elsif ($graph eq 'rep_histo' and $arg->{where}) {
318 my $dir = $arg->{where};
319 $dir .= '/' if ($dir !~ m!/$!);
320 $dir = $dbh->quote($dir);
323 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
324 Client.Name AS client,
326 brestore_pathvisibility.size AS size
328 FROM Job, Client, FileSet, Path, brestore_pathvisibility
329 WHERE Job.ClientId = Client.ClientId
330 AND Job.FileSetId = FileSet.FileSetId
332 AND Job.JobId = brestore_pathvisibility.JobId
333 AND Path.PathId = brestore_pathvisibility.PathId
343 print STDERR $query if ($debug);
345 my $all = $dbh->selectall_arrayref($query) ;
347 my $obj = get_graph('title' => "Directory size : $arg->{where}",
348 'y_label' => 'Directory size',
351 'y_number_format' => \&Bweb::human_size,
355 my ($d, $ret) = make_tab($all);
357 $obj->set_legend(keys %$ret);
359 print $obj->plot([$d, values %$ret])->png;
362 elsif ($graph eq 'job_rate') {
366 UNIX_TIMESTAMP($jobt.StartTime) AS starttime,
367 Client.Name AS clientname,
368 $jobt.Name AS jobname,
370 ($bweb->{sql}->{SEC_TO_INT}(
371 $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)
372 - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01)
375 FROM $jobt, Client, FileSet
376 WHERE $jobt.ClientId = Client.ClientId
377 AND $jobt.FileSetId = FileSet.FileSetId
387 print STDERR $query if ($debug);
389 my $obj = get_graph('title' => "Job Rate : $arg->{jclients}/$arg->{jjobnames}",
390 'y_label' => 'Rate b/s',
392 'y_number_format' => \&Bweb::human_size,
395 my $all = $dbh->selectall_arrayref($query) ;
397 my ($d, $ret) = make_tab($all);
399 $obj->set_legend(keys %$ret);
401 print $obj->plot([$d, values %$ret])->png;
406 elsif ($graph eq 'job_duration') {
410 UNIX_TIMESTAMP($jobt.StartTime) AS starttime,
411 Client.Name AS clientname,
412 $jobt.Name AS jobname,
413 $bweb->{sql}->{SEC_TO_INT}( $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)
414 - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime))
416 FROM $jobt, Client, FileSet
417 WHERE $jobt.ClientId = Client.ClientId
418 AND $jobt.FileSetId = FileSet.FileSetId
428 print STDERR $query if ($debug);
430 my $obj = get_graph('title' => "Job Duration : $arg->{jclients}/$arg->{jjobnames}",
431 'y_label' => 'Duration',
433 'y_number_format' => \&Bweb::human_sec,
435 my $all = $dbh->selectall_arrayref($query) ;
437 my ($d, $ret) = make_tab($all);
439 $obj->set_legend(keys %$ret);
441 print $obj->plot([$d, values %$ret])->png;
444 # number of job per day/hour
445 } elsif ($graph =~ /^job_(count|sum|avg)_((p?)(day|hour|month))$/) {
449 my ($limit, $label) = $bweb->get_limit(age => $arg->{age},
450 limit => $arg->{limit},
451 offset=> $arg->{offset},
454 my @arg; # arg for plotting
456 if (!$per_t) { # much better aspect
459 push @arg, ("x_number_format" => undef,
464 if ($t eq 'sum' or $t eq 'avg') {
465 push @arg, ('y_number_format' => \&Bweb::human_size);
468 my $stime = $bweb->{sql}->{"STARTTIME_$d"};
469 $stime =~ s/Job\./$jobt\./;
473 " . ($per_t?"":"UNIX_TIMESTAMP") . "($stime) AS A,
475 FROM $jobt, Client, FileSet
476 WHERE $jobt.ClientId = Client.ClientId
477 AND $jobt.FileSetId = FileSet.FileSetId
487 print STDERR $query if ($debug);
489 my $obj = get_graph('title' => "Job $t : $arg->{jclients}/$arg->{jjobnames}",
495 my $all = $dbh->selectall_arrayref($query) ;
496 my ($ret) = make_tab_sum($all);
498 print $obj->plot([$ret->{date}, $ret->{nb}])->png;