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);
52 my $bweb = new Bweb(info => $conf);
54 my $dbh = $bweb->{dbh};
55 my $debug = $bweb->{debug};
57 my $graph = CGI::param('graph') || 'job_size';
58 my $legend = CGI::param('legend') || 'on' ;
59 $legend = ($legend eq 'on')?1:0;
61 my $arg = $bweb->get_form(qw/width height limit offset age where jobid
62 jfilesets level status jjobnames jclients/);
64 my ($limitq, $label) = $bweb->get_limit(age => $arg->{age},
65 limit => $arg->{limit},
66 offset=> $arg->{offset},
67 order => 'Job.StartTime ASC',
71 if ($arg->{status} and $arg->{status} ne 'Any') {
72 $statusq = " AND Job.JobStatus = '$arg->{status}' ";
76 if ($arg->{level} and $arg->{level} ne 'Any') {
77 $levelq = " AND Job.Level = '$arg->{level}' ";
81 if ($arg->{jfilesets}) {
82 $filesetq = " AND FileSet.FileSet IN ($arg->{qfilesets}) ";
86 if ($arg->{jjobnames}) {
87 $jobnameq = " AND Job.Name IN ($arg->{jjobnames}) ";
89 $arg->{jjobnames} = 'all'; # skip warning
93 if ($arg->{jclients}) {
94 $clientq = " AND Client.Name IN ($arg->{jclients}) ";
96 $arg->{jclients} = 'all'; # skip warning
99 my $gtype = CGI::param('gtype') || 'bars';
101 print CGI::header('image/png');
107 if ($gtype eq 'lines') {
108 use GD::Graph::lines;
109 $graph = GD::Graph::lines->new ( $arg->{width}, $arg->{height} );
111 } elsif ($gtype eq 'bars') {
113 $graph = GD::Graph::bars->new ( $arg->{width}, $arg->{height} );
115 } elsif ($gtype eq 'linespoints') {
116 use GD::Graph::linespoints;
117 $graph = GD::Graph::linespoints->new ( $arg->{width}, $arg->{height} );
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} );
128 $graph->set('x_label' => 'Time',
129 'x_number_format' => sub { strftime('%D', localtime($_[0])) },
130 'x_tick_number' => 1,
146 foreach my $row (@$all_row) {
147 my $label = $row->[1] . "/" . $row->[2] ; # client/backup name
149 $ret->{date}->[$i] = $row->[0];
150 $ret->{$label}->[$i] = $row->[3];
152 $last_date = $row->[0];
155 # insert a fake element
156 foreach my $elt ( keys %{$ret}) {
157 $ret->{$elt}->[$i] = undef;
160 $ret->{date}->[$i] = $last_date + 1;
162 my $date = $ret->{date} ;
165 return ($date, $ret);
177 foreach my $row (@$all_row) {
178 $ret->{date}->[$i] = $row->[0];
179 $ret->{nb}->[$i] = $row->[1];
186 if ($graph eq 'job_size') {
190 UNIX_TIMESTAMP(Job.StartTime) AS starttime,
191 Client.Name AS clientname,
193 Job.JobBytes AS jobbytes
194 FROM Job, Client, FileSet
195 WHERE Job.ClientId = Client.ClientId
196 AND Job.FileSetId = FileSet.FileSetId
206 print STDERR $query if ($debug);
208 my $obj = get_graph('title' => "Job Size : $arg->{jclients}/$arg->{jjobnames}",
211 'y_number_format' => \&Bweb::human_size,
214 my $all = $dbh->selectall_arrayref($query) ;
216 my ($d, $ret) = make_tab($all);
218 $obj->set_legend(keys %$ret);
220 print $obj->plot([$d, values %$ret])->png;
223 if ($graph eq 'job_file') {
227 UNIX_TIMESTAMP(Job.StartTime) AS starttime,
228 Client.Name AS clientname,
230 Job.JobFiles AS jobfiles
231 FROM Job, Client, FileSet
232 WHERE Job.ClientId = Client.ClientId
233 AND Job.FileSetId = FileSet.FileSetId
243 print STDERR $query if ($debug);
245 my $obj = get_graph('title' => "Job Files : $arg->{jclients}/$arg->{jjobnames}",
246 'y_label' => 'Number Files',
250 my $all = $dbh->selectall_arrayref($query) ;
252 my ($d, $ret) = make_tab($all);
254 $obj->set_legend(keys %$ret);
256 print $obj->plot([$d, values %$ret])->png;
259 # it works only with postgresql at this time
260 elsif ($graph eq 'file_histo' and $arg->{where}) {
262 my $dir = $dbh->quote(dirname($arg->{where}) . '/');
263 my $file = $dbh->quote(basename($arg->{where}));
266 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
267 Client.Name AS client,
269 base64_decode_lstat(8,LStat) AS lstat
271 FROM Job, Client, FileSet, Filename, Path, File
272 WHERE Job.ClientId = Client.ClientId
273 AND Job.FileSetId = FileSet.FileSetId
275 AND File.JobId = Job.JobId
276 AND File.FilenameId = Filename.FilenameId
277 AND File.PathId = Path.PathId
279 AND Filename.Name = $file
288 print STDERR $query if ($debug);
290 my $all = $dbh->selectall_arrayref($query) ;
292 my $obj = get_graph('title' => "File size : $arg->{where}",
293 'y_label' => 'File size',
296 'y_number_format' => \&Bweb::human_size,
300 my ($d, $ret) = make_tab($all);
302 $obj->set_legend(keys %$ret);
304 print $obj->plot([$d, values %$ret])->png;
307 # it works only with postgresql at this time
308 # TODO: use brestore_missing_path
309 elsif ($graph eq 'rep_histo' and $arg->{where}) {
311 my $dir = $arg->{where};
312 $dir .= '/' if ($dir !~ m!/$!);
313 $dir = $dbh->quote($dir);
316 SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
317 Client.Name AS client,
319 brestore_pathvisibility.size AS size
321 FROM Job, Client, FileSet, Path, brestore_pathvisibility
322 WHERE Job.ClientId = Client.ClientId
323 AND Job.FileSetId = FileSet.FileSetId
325 AND Job.JobId = brestore_pathvisibility.JobId
326 AND Path.PathId = brestore_pathvisibility.PathId
336 print STDERR $query if ($debug);
338 my $all = $dbh->selectall_arrayref($query) ;
340 my $obj = get_graph('title' => "Directory size : $arg->{where}",
341 'y_label' => 'Directory size',
344 'y_number_format' => \&Bweb::human_size,
348 my ($d, $ret) = make_tab($all);
350 $obj->set_legend(keys %$ret);
352 print $obj->plot([$d, values %$ret])->png;
355 elsif ($graph eq 'job_rate') {
359 UNIX_TIMESTAMP(Job.StartTime) AS starttime,
360 Client.Name AS clientname,
363 ($bweb->{sql}->{SEC_TO_INT}(
364 $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)
365 - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01)
368 FROM Job, Client, FileSet
369 WHERE Job.ClientId = Client.ClientId
370 AND Job.FileSetId = FileSet.FileSetId
380 print STDERR $query if ($debug);
382 my $obj = get_graph('title' => "Job Rate : $arg->{jclients}/$arg->{jjobnames}",
383 'y_label' => 'Rate b/s',
385 'y_number_format' => \&Bweb::human_size,
388 my $all = $dbh->selectall_arrayref($query) ;
390 my ($d, $ret) = make_tab($all);
392 $obj->set_legend(keys %$ret);
394 print $obj->plot([$d, values %$ret])->png;
399 elsif ($graph eq 'job_duration') {
403 UNIX_TIMESTAMP(Job.StartTime) AS starttime,
404 Client.Name AS clientname,
406 $bweb->{sql}->{SEC_TO_INT}( $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)
407 - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime))
409 FROM Job, Client, FileSet
410 WHERE Job.ClientId = Client.ClientId
411 AND Job.FileSetId = FileSet.FileSetId
421 print STDERR $query if ($debug);
423 my $obj = get_graph('title' => "Job Duration : $arg->{jclients}/$arg->{jjobnames}",
424 'y_label' => 'Duration',
426 'y_number_format' => \&Bweb::human_sec,
428 my $all = $dbh->selectall_arrayref($query) ;
430 my ($d, $ret) = make_tab($all);
432 $obj->set_legend(keys %$ret);
434 print $obj->plot([$d, values %$ret])->png;
437 # number of job per day/hour
438 } elsif ($graph =~ /^job_(count|sum|avg)_((p?)(day|hour|month))$/) {
442 my ($limit, $label) = $bweb->get_limit(age => $arg->{age},
443 limit => $arg->{limit},
444 offset=> $arg->{offset},
447 my @arg; # arg for plotting
449 if (!$per_t) { # much better aspect
452 push @arg, ("x_number_format" => undef,
457 if ($t eq 'sum' or $t eq 'avg') {
458 push @arg, ('y_number_format' => \&Bweb::human_size);
463 " . ($per_t?"":"UNIX_TIMESTAMP") . "(" . $bweb->{sql}->{"STARTTIME_$d"} . ") AS A,
465 FROM Job, Client, FileSet
466 WHERE Job.ClientId = Client.ClientId
467 AND Job.FileSetId = FileSet.FileSetId
477 print STDERR $query if ($debug);
479 my $obj = get_graph('title' => "Job $t : $arg->{jclients}/$arg->{jjobnames}",
485 my $all = $dbh->selectall_arrayref($query) ;
486 my ($ret) = make_tab_sum($all);
488 print $obj->plot([$ret->{date}, $ret->{nb}])->png;