55c6a62a85998e88fcd82e1239113e2d57e645c2
[upsgraph] / upsgraph.pl
1 #!/usr/bin/perl -w
2
3 #Due to memory leak in Debian squeeze (Bug #545519)
4 my $use_rrds = 0;
5 my $rrd_result = 0;
6
7 if ((@ARGV != 1) && (@ARGV != 2)) {
8 print STDERR "Syntax: ${0} configfile [uid]\n";
9 exit(1);
10 }
11
12 use Net::SNMP;
13 use IO::Socket::INET;
14 use IO::Select;
15 use RRDs;
16 use File::Copy;
17 use Data::Dumper;
18 use LWP::UserAgent;
19 use JSON;
20
21 $UPSGRAPH::outdir = "";
22 $UPSGRAPH::daysCovered = 370;
23 $UPSGRAPH::step = 60;
24 $UPSGRAPH::stepsPerHour = (60 * 60) / $UPSGRAPH::step;
25 $UPSGRAPH::keep = ($UPSGRAPH::daysCovered*24*60*60)/$UPSGRAPH::step;
26 $UPSGRAPH::keepHours = ($UPSGRAPH::daysCovered*24*60*60)/$UPSGRAPH::stepsPerHour/$UPSGRAPH::step;
27 $UPSGRAPH::hosts = ();
28 $UPSGRAPH::regenerateOnStart = 1; #when set, regenerate graphs on script startup
29
30 do $ARGV[0] or die "can't read config: $!";
31
32 my $outdir = $UPSGRAPH::outdir;
33 my $step = $UPSGRAPH::step;
34 my $stepsPerHour = $UPSGRAPH::stepsPerHour;
35 my $keep = $UPSGRAPH::keep;
36 my $keepHours = $UPSGRAPH::keepHours;
37 my $hosts = $UPSGRAPH::hosts;
38
39 sub rrd_update(@) {
40 my @args = @_;
41
42 if ($use_rrds == 1) {
43 RRDs::update(@args);
44 $rrd_result = RRDs::error;
45 } else {
46 $rrd_result = system("rrdtool", "update", @args);
47 }
48 }
49
50 sub rrd_graph(@) {
51 my @args = @_;
52 my @rrd_out = ();
53
54 if ($use_rrds == 1) {
55 @rrd_out = RRDs::graph(@args);
56 $rrd_result = RRDs::error;
57 } else {
58 my $rrd_stdout;
59
60 open(RRDFD, '-|', 'rrdtool', 'graph', @args);
61 while(<RRDFD>) {
62 chomp;
63 $rrd_stdout = $_;
64 }
65 close(RRDFD);
66 $rrd_result = $?;
67 if ($rrd_result == 0) {
68 push @rrd_out, 0;
69 push @rrd_out, split(/x/, $rrd_stdout);
70 }
71 }
72
73 return @rrd_out;
74 }
75
76 sub rrdcreate(@) {
77 my $newrrd = shift;
78 my $field = shift;
79 my $vars = shift;
80 my $start = shift;
81
82 my @cmd = ("${newrrd}", "--step=${step}");
83
84 if (defined($start)) {
85 push @cmd, "--start=${start}";
86 }
87
88 push @cmd, "DS:${field}:GAUGE:600:" .
89 $vars->{$field}->{'min'} . ":" .
90 $vars->{$field}->{'max'};
91
92 push @cmd, "RRA:AVERAGE:0.5:1:${keep}";
93 push @cmd, "RRA:MIN:0.4:${stepsPerHour}:${keepHours}";
94 push @cmd, "RRA:MAX:0.4:${stepsPerHour}:${keepHours}";
95 push @cmd, "RRA:AVERAGE:0.5:${stepsPerHour}:${keepHours}";
96
97 RRDs::create(@cmd);
98 if (RRDs::error) {
99 print "Error while creating: " . RRDs::error . "\n";
100 exit 1;
101 }
102 }
103
104 sub fetch_snmp(@) {
105 my $address = shift;
106 my $community = shift;
107 my $oid = shift;
108
109 (my $session, my $error) = Net::SNMP->session(Hostname => $address,
110 Community => $community);
111
112 if (!$session) {
113 print STDERR "session error: $error";
114 return undef;
115 }
116
117 $session->translate(0);
118
119 my $result = $session->get_request($oid);
120
121 $session->close;
122
123 return undef if (!defined($result));
124
125 $result->{$oid};
126 }
127
128 sub fetch_tcp(@) {
129 my $address = shift;
130 my $port = shift;
131
132 my $sock = IO::Socket::INET->new(PeerAddr => $address,
133 PeerPort => $port,
134 Proto => 'tcp',
135 Timeout => 1);
136
137 return undef if (!$sock);
138
139 my $select = IO::Select->new($sock);
140
141 my $value = undef;
142
143 if ($select->can_read(1)) {
144 chomp($value) if (sysread($sock, $value, 4096) > 0);
145 }
146
147 close($sock);
148
149 if (!$value) {
150 return undef;
151 }
152
153 $value=~ s/\s//g;
154
155 $value;
156 }
157
158 sub fetch_tcp_multi(@) {
159 my $address = shift;
160 my $port = shift;
161 my $delimiter = shift;
162 my %values;
163
164 my $sock = IO::Socket::INET->new(PeerAddr => $address,
165 PeerPort => $port,
166 Proto => 'tcp',
167 Timeout => 1);
168
169 return undef if (!$sock);
170
171 my $select = IO::Select->new($sock);
172
173 while($select->can_read(1)) {
174 if (sysread($sock, my $buf, 16384) > 0) {
175 $buf=~s/\r//g;
176 foreach my $line (split(/\n/, $buf)) {
177 (my $key, my $value) = split(/${delimiter}/, $line);
178 $value=~ s/\s//g;
179 $values{$key} = $value;
180 }
181 } else {
182 last;
183 }
184 }
185
186 close($sock);
187
188 %values;
189 }
190
191 sub fetch_iotcore(@) {
192 my $url = shift;
193
194 my $ua = LWP::UserAgent->new;
195 $ua->timeout(1);
196
197 my $resp = $ua->get($url);
198 return undef if (!$resp->is_success);
199
200 my $pdin = decode_json($resp->decoded_content);
201 return undef if (!defined($pdin));
202
203 my $value = hex($pdin->{'data'}->{'value'});
204
205 $value;
206 }
207
208 sub dayGraphFunc {
209 my $dataSrc = shift;
210 my $mode = shift;
211 my $color = shift;
212 my $label = shift;
213 my $dataPoints = shift;
214 my @args = ();
215 push @args, "CDEF:prev${mode}1=PREV(${dataSrc})";
216 for (my $i = 1; $i < $dataPoints - 1; ++$i) {
217 my $prev = $i;
218 my $next = $i+1;
219 push @args, "CDEF:prev${mode}${next}=PREV(prev${mode}${prev})";
220 }
221 my $dayCons = '';
222 my $consFunc = '';
223 if ($mode ne 'AVG') {
224 for (my $i = 1; $i < $dataPoints; ++$i) {
225 $dayCons .= "prev${mode}${i},";
226 $consFunc .= ",${mode}";
227 }
228 } else {
229 for (my $i = 1; $i < $dataPoints; ++$i) {
230 $dayCons .= "prev${mode}${i},";
231 }
232 $consFunc = ",${dataPoints},${mode}";
233 }
234 push @args, "CDEF:day${mode}=${dayCons}${dataSrc}${consFunc}";
235 push @args, "CDEF:fillCalDay${mode}0=COUNT,${dataPoints},%,0,EQ,day${mode},UNKN,IF";
236 for (my $i = 1; $i < $dataPoints; ++$i) {
237 my $prev = $i-1;
238 my $next = $i;
239 push @args, "CDEF:fillCalDay${mode}${next}=PREV(fillCalDay${mode}${prev})";
240 }
241 my $fillPoint = '';
242 my $if = '';
243 for (my $i = 0; $i < $dataPoints; ++$i) {
244 $fillPoint .= "COUNT,${dataPoints},%,${i},EQ,fillCalDay${mode}${i},";
245 $if .= ",IF";
246 }
247 push @args, "CDEF:${mode}Curve=${fillPoint}UNKN${if}";
248 my $forwardShift = (24*60*60) * ($dataPoints - 1) / $dataPoints;
249 push @args, "SHIFT:${mode}Curve:-${forwardShift}";
250 push @args, "LINE1:${mode}Curve#${color}:${label}";
251 return \@args;
252 }
253
254 sub cfgToGraphDef {
255 my $cfg = shift;
256 my $varname = shift;
257 my $dpPerDay= shift;
258 my @graphDef = ();
259 foreach my $subGraph (@$cfg) {
260 if ($subGraph eq 'avg') {
261 push @graphDef, "LINE1:${varname}-avg#FF0000";
262 } elsif ($subGraph eq 'day-min') {
263 push @graphDef, @{dayGraphFunc("${varname}-min", 'MIN', '0000ff', 'Day Minimum Temperature', $dpPerDay)};
264 } elsif ($subGraph eq 'day-max') {
265 push @graphDef, @{dayGraphFunc("${varname}-max", 'MAX', '00ff00', 'Day Maximum Temperature', $dpPerDay)};
266 } elsif ($subGraph eq 'day-avg') {
267 push @graphDef, @{dayGraphFunc("${varname}-houravg", 'AVG', 'ff0000', 'Day Average Temperature', $dpPerDay)};
268 }
269 }
270 return \@graphDef;
271 }
272
273 if ($> == 0) {
274 if (@ARGV != 2) {
275 print STDERR "Running as root, please provide UID as 2th argument!\n";
276 exit(1);
277 }
278
279 print "Running as root, switching to ".$ARGV[1]."\n";
280 $< = $> = $ARGV[1];
281 }
282
283 foreach my $host (@$hosts) {
284 my $rrdfile = $host->{'rrdfile'};
285
286 foreach my $var (keys(%{$host->{'vars'}})) {
287 $host->{'vars'}->{$var}->{'min'} = 'U' if (!defined($host->{'vars'}->{$var}->{'min'}));
288 $host->{'vars'}->{$var}->{'max'} = 'U' if (!defined($host->{'vars'}->{$var}->{'max'}));
289 }
290
291 if (-e "${rrdfile}") {
292 print "Reading old ${rrdfile} to preserve data...\n";
293
294 my $rrdinfo = RRDs::info("${rrdfile}");
295 if (RRDs::error) {
296 print "Error while getting info: " . RRDs::error . "\n";
297 exit 1;
298 }
299
300 (my $start, my $ostep, my $names, my $data) =
301 RRDs::fetch("${rrdfile}",
302 "-s " . (time() - ($rrdinfo->{'rra[0].rows'} * $rrdinfo->{'step'})),
303 "AVERAGE");
304
305 if (RRDs::error) {
306 print "Error while fetching data: " . RRDs::error . "\n";
307 exit 1;
308 }
309
310 foreach my $field (@$names) {
311 if (! -e "${rrdfile}.${field}") {
312 rrdcreate("${rrdfile}.${field}",
313 "${field}",
314 $host->{'vars'},
315 (${start}-${ostep}));
316 }
317 }
318
319 my $pos = $start;
320 foreach my $line (@$data) {
321 foreach my $field (@$names) {
322 my $val = shift (@$line);
323 $val = 'U' if (!defined($val));
324
325 RRDs::update("${rrdfile}.${field}", "${pos}:${val}");
326 if (RRDs::error) {
327 print "Can't insert data: " . RRDs::error . "\n";
328 exit 1;
329 }
330
331 }
332
333 $pos += $ostep;
334
335 if ((($pos-$start)/$ostep) == $#$data) {
336 last;
337 }
338 }
339
340 rename("${rrdfile}", "${rrdfile}.old") or die "Can't rename old file: $!\n";
341 }
342
343 foreach my $field (@{$host->{'fields'}}) {
344 if (! -e "${rrdfile}.${field}") {
345 print "Creating ${rrdfile}.${field}...\n";
346 rrdcreate("${rrdfile}.${field}",
347 "${field}",
348 $host->{'vars'});
349 }
350
351 my $rrdinfo = RRDs::info("${rrdfile}.${field}");
352 if (RRDs::error) {
353 print "Error while getting info: " . RRDs::error . "\n";
354 exit 1;
355 }
356
357 my $limitsChanged = 0;
358 if (defined($rrdinfo->{"ds[${field}].min"})) {
359 if ($rrdinfo->{"ds[${field}].min"} ne $host->{'vars'}->{$field}->{'min'}) {
360 $limitsChanged = 1;
361 RRDs::tune("${rrdfile}.${field}","-i",$field.":".$host->{'vars'}->{$field}->{'min'});
362 }
363 } else {
364 if ($host->{'vars'}->{$field}->{'min'} ne 'U') {
365 $limitsChanged = 1;
366 RRDs::tune("${rrdfile}.${field}","-i",$field.":".$host->{'vars'}->{$field}->{'min'});
367 }
368 }
369
370 if (RRDs::error) {
371 print "Error while setting min: " . RRDs::error . "\n";
372 exit 1;
373 }
374
375 if (defined($rrdinfo->{"ds[${field}].max"})) {
376 if ($rrdinfo->{"ds[${field}].max"} ne $host->{'vars'}->{$field}->{'max'}) {
377 $limitsChanged = 1;
378 RRDs::tune("${rrdfile}.${field}","-a",$field.":".$host->{'vars'}->{$field}->{'max'});
379 }
380 } else {
381 if ($host->{'vars'}->{$field}->{'max'} ne 'U') {
382 $limitsChanged = 1;
383 RRDs::tune("${rrdfile}.${field}","-a",$field.":".$host->{'vars'}->{$field}->{'max'});
384 }
385 }
386
387 if (RRDs::error) {
388 print "Error while setting max: " . RRDs::error . "\n";
389 exit 1;
390 }
391
392 if ($rrdinfo->{'rra[0].rows'} != $keep ||
393 !defined($rrdinfo->{'rra[3].rows'}) || $rrdinfo->{'rra[3].rows'} != $keepHours ||
394 $limitsChanged == 1) {
395
396 print "Resizing ${rrdfile}.${field} from " . $rrdinfo->{'rra[0].rows'} .
397 " to ${keep} samples.\n";
398
399 (my $start, my $ostep, my $names, my $data) =
400 RRDs::fetch("${rrdfile}.${field}",
401 "-s " . (time() - ($rrdinfo->{'rra[0].rows'} * $rrdinfo->{'step'})),
402 "AVERAGE");
403
404 if (RRDs::error) {
405 print "Error while fetching data: " . RRDs::error . "\n";
406 exit 1;
407 }
408
409 rrdcreate("${rrdfile}.${field}.new",
410 "${field}",
411 $host->{'vars'},
412 (${start}-${ostep}));
413
414 print "Preserving data in file ${rrdfile}.${field} since " . localtime($start) . "\n";
415
416 my $pos = $start;
417 foreach my $line (@$data) {
418 my $vline = "${pos}";
419
420 foreach my $val (@$line) {
421 $val = 'U' if (!defined($val));
422 $vline .= ":${val}";
423 }
424 RRDs::update("${rrdfile}.${field}.new", $vline) or die "Can't insert data\n";
425
426 if (RRDs::error) {
427 print "Error while updating: " . RRDs::error . "\n";
428 exit 1;
429 }
430 $pos += $ostep;
431
432 if ((($pos-$start)/$ostep) == $#$data) {
433 last;
434 }
435 }
436
437 rename("${rrdfile}.${field}", "${rrdfile}.${field}.old") or die "Can't rename old file: $!\n";
438 rename("${rrdfile}.${field}.new", "${rrdfile}.${field}") or die "Can't rename new file: $!\n";
439
440 $rrdinfo = RRDs::info("${rrdfile}.${field}");
441 if (RRDs::error) {
442 print "Error while getting info: " . RRDs::error . "\n";
443 exit 1;
444 }
445
446 if ($rrdinfo->{'rra[0].rows'} != $keep) {
447 print "Failed!\n";
448 exit 1;
449 }
450 }
451 }
452 }
453
454 my $child = fork();
455
456 die "fork failed!" if (!defined($child));
457
458 exit 0 if ($child != 0);
459
460 my $first = $UPSGRAPH::regenerateOnStart;
461 while(1) {
462 open(HTML, ">${outdir}/index.html.new");
463
464 print HTML '<html><head><meta http-equiv="refresh" content="60"/><meta http-equiv="cache-control" content="no-cache"/><meta http-equiv="pragma" content="no-cache"/><meta http_equiv="expires" content="Sat, 26 Jul 1997 05:00:00 GMT"/><title>Status</title></head>';
465 print HTML '<body bgcolor="#ffffff">';
466
467 foreach my $host (@$hosts) {
468 print HTML "[<a href=\"#".${host}->{'name'}."\">".${host}->{'name'}."</a>]&nbsp;";
469 }
470 print HTML "<br>\n";
471
472 foreach my $host (@$hosts) {
473 print HTML "<br>\n";
474 print HTML "<a name=\"".${host}->{'name'}."\"></a>\n";
475 my $vars = $host->{'vars'};
476 my $rrdfile = $host->{'rrdfile'};
477 my $hostname = $host->{'name'};
478 my %multi_values = ();
479
480 foreach my $var (@{$host->{'fields'}}) {
481 delete $vars->{$var}->{'value'};
482
483 my $result;
484
485 if ((!defined($vars->{$var}->{'proto'})) ||
486 ($vars->{$var}->{'proto'} eq '') ||
487 ($vars->{$var}->{'proto'} eq 'snmp')) {
488 $result = fetch_snmp($host->{'address'}, $host->{'community'}, $vars->{$var}->{'oid'});
489 } elsif ($vars->{$var}->{'proto'} eq 'tcp') {
490 $result = fetch_tcp($host->{'address'}, $vars->{$var}->{'port'});
491 } elsif ($vars->{$var}->{'proto'} eq 'tcp_multi') {
492 if (defined($multi_values{$vars->{$var}->{'multi_id'}})) {
493 $result = $multi_values{$vars->{$var}->{'multi_id'}}
494 } else {
495 my %values = fetch_tcp_multi($host->{'address'}, $vars->{$var}->{'port'}, $vars->{$var}->{'multi_delimiter'});
496 @multi_values{keys %values} = values %values;
497 $result = $multi_values{$vars->{$var}->{'multi_id'}};
498 }
499 } elsif ($vars->{$var}->{'proto'} eq 'iotcore') {
500 $result = fetch_iotcore($vars->{$var}->{'url'});
501 }
502
503 next unless (defined $result);
504
505 $vars->{$var}->{'value'} = $result;
506 if (defined($vars->{$var}->{'factor'})) {
507 $vars->{$var}->{'value'} *= $vars->{$var}->{'factor'};
508 }
509 }
510
511 foreach my $var (@{$host->{'fields'}}) {
512 if (!(defined($vars->{$var}->{'value'}))) {
513 $vars->{$var}->{'value'} = 'U';
514 }
515 rrd_update("${rrdfile}.${var}", "N:" . $vars->{$var}->{'value'});
516 }
517 if ($rrd_result) {
518 print "Error while updating: " . $rrd_result . "\n";
519 }
520
521 foreach my $var (@{$host->{'fields'}}) {
522 my $graphWidth = 365 * 3;
523 my $graphConfig;
524 if (defined $vars->{$var}->{'graph'}) {
525 $graphConfig = $vars->{$var}->{'graph'};
526 foreach my $subGraph (qw(day week year)) {
527 if (!defined($graphConfig->{$subGraph})) {
528 $graphConfig->{$subGraph} = [ 'avg'];
529 }
530 }
531 } else {
532 $graphConfig = {
533 'day' => [ 'avg' ],
534 'week' => [ 'avg' ],
535 'year' => [ 'avg' ],
536 };
537 }
538
539 my @graphdef = ('-P', "-A", "-t", $hostname." - ".$vars->{$var}->{'name'});
540 push @graphdef, "--lazy" if !$first;
541
542 push @graphdef, "DEF:${var}-avg=${rrdfile}.${var}:${var}:AVERAGE";
543 push @graphdef, "DEF:${var}-min=${rrdfile}.${var}:${var}:MIN";
544 push @graphdef, "DEF:${var}-max=${rrdfile}.${var}:${var}:MAX";
545 push @graphdef, "DEF:${var}-houravg=${rrdfile}.${var}:${var}:AVERAGE:step=3600";
546 push @graphdef, "LINE1:${var}-avg#FF0000";
547 push @graphdef, "VDEF:cur=${var}-avg,LAST";
548 push @graphdef, 'GPRINT:cur:Current\\: <span foreground="#FF0000">%.2lf</span>\\r';
549
550 my $mtime;
551 $mtime=(stat("${outdir}/${hostname}.${var}.png.work"))[9];
552
553 (my $averages, my $width, my $height) =
554 rrd_graph("${outdir}/${hostname}.${var}.png.work",
555 "-w", "720", @graphdef);
556
557 pop @graphdef;
558 pop @graphdef;
559 pop @graphdef;
560
561 if ($rrd_result) {
562 print "Error while graphing: " . $rrd_result . "\n";
563 } else {
564 my $newmtime=(stat("${outdir}/${hostname}.${var}.png.work"))[9];
565 if ((!defined($mtime)) || ($newmtime != $mtime)) {
566 copy("${outdir}/${hostname}.${var}.png.work", "${outdir}/${hostname}.${var}.png.new");
567 rename("${outdir}/${hostname}.${var}.png.new", "${outdir}/${hostname}.${var}.png");
568 }
569 }
570
571 print HTML "<a href=\"${hostname}.${var}.html\"><img src=\"${hostname}.${var}.png\" width=\"${width}\" height=\"${height}\" border=\"0\"></a><br>\n";
572
573 open (HTML2, ">${outdir}/${hostname}.${var}.html.new");
574 print HTML2 '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="refresh" content="60"/><meta http-equiv="cache-control" content="no-cache"/><meta http-equiv="pragma" content="no-cache"/><meta http_equiv="expires" content="Sat, 26 Jul 1997 05:00:00 GMT"/><title>' . $vars->{$var}->{'name'} . '</title></head>';
575 print HTML2 '<body bgcolor="#ffffff">';
576
577 push @graphdef, "VDEF:min=${var}-min,MINIMUM";
578 push @graphdef, "GPRINT:min:Minimum\\: %.2lf";
579
580 push @graphdef, "VDEF:avg=${var}-avg,AVERAGE";
581 push @graphdef, "GPRINT:avg:Average\\: %.2lf";
582
583 push @graphdef, "VDEF:max=${var}-max,MAXIMUM";
584 push @graphdef, "GPRINT:max:Maximum\\: %.2lf";
585
586 push @graphdef, "VDEF:cur=${var}-avg,LAST";
587 push @graphdef, "GPRINT:cur:Current\\: %.2lf";
588
589 my @dayGraphDef = @graphdef;
590 push @dayGraphDef, @{cfgToGraphDef($graphConfig->{'day'}, ${var}, 24)};
591
592 $mtime=(stat("${outdir}/${hostname}.${var}.long.png.work"))[9];
593 ($averages, $width, $height) =
594 rrd_graph("${outdir}/${hostname}.${var}.long.png.work",
595 "-w", $graphWidth, @dayGraphDef);
596
597 if ($rrd_result) {
598 print "Error while graphing: " . $rrd_result . "\n";
599 } else {
600 my $newmtime=(stat("${outdir}/${hostname}.${var}.long.png.work"))[9];
601 if ((!defined($mtime)) || ($newmtime != $mtime)) {
602 copy("${outdir}/${hostname}.${var}.long.png.work", "${outdir}/${hostname}.${var}.long.png.new");
603 rename("${outdir}/${hostname}.${var}.long.png.new", "${outdir}/${hostname}.${var}.long.png");
604 }
605 }
606
607 print HTML2 "<img src=\"${hostname}.${var}.long.png\" width=\"${width}\" height=\"${height}\"><br>\n";
608
609 $mtime=(stat("${outdir}/${hostname}.${var}.week.png.work"))[9];
610
611 my @weekGraphDef = @graphdef;
612 push @weekGraphDef, @{cfgToGraphDef($graphConfig->{'week'}, ${var}, 24)};
613
614 ($averages, $width, $height) =
615 rrd_graph("${outdir}/${hostname}.${var}.week.png.work",
616 "-w", "$graphWidth", "-e", "now", "-s", "00:00-8d", @weekGraphDef);
617
618 if ($rrd_result) {
619 print "Error while graphing: " . $rrd_result . "\n";
620 } else {
621 my $newmtime=(stat("${outdir}/${hostname}.${var}.week.png.work"))[9];
622 if ((!defined($mtime)) || ($newmtime != $mtime)) {
623 copy("${outdir}/${hostname}.${var}.week.png.work", "${outdir}/${hostname}.${var}.week.png.new");
624 rename("${outdir}/${hostname}.${var}.week.png.new", "${outdir}/${hostname}.${var}.week.png");
625 }
626 }
627
628 print HTML2 "<img src=\"${hostname}.${var}.week.png\" width=\"${width}\" height=\"${height}\"><br>\n";
629
630 $mtime=(stat("${outdir}/${hostname}.${var}.year.png.work"))[9];
631
632 my @yearGraphDef = @graphdef;
633 push @yearGraphDef, @{cfgToGraphDef($graphConfig->{'year'}, ${var}, 3)};
634
635 ($averages, $width, $height) =
636 rrd_graph("${outdir}/${hostname}.${var}.year.png.work",
637 "-w", "$graphWidth", "-e", "00:00", "-s", "end-365d", @yearGraphDef);
638
639 if ($rrd_result) {
640 print "Error while graphing: " . $rrd_result . "\n";
641 } else {
642 my $newmtime=(stat("${outdir}/${hostname}.${var}.year.png.work"))[9];
643 if ((!defined($mtime)) || ($newmtime != $mtime)) {
644 copy("${outdir}/${hostname}.${var}.year.png.work", "${outdir}/${hostname}.${var}.year.png.new");
645 rename("${outdir}/${hostname}.${var}.year.png.new", "${outdir}/${hostname}.${var}.year.png");
646 }
647 }
648
649 print HTML2 "<img src=\"${hostname}.${var}.year.png\" width=\"${width}\" height=\"${height}\"><br>\n";
650
651 print HTML2 "</body></html>\n";
652 close(HTML2);
653 rename("${outdir}/${hostname}.${var}.html.new", "${outdir}/${hostname}.${var}.html");
654 }
655 }
656
657 print HTML "</body></html>\n";
658 print HTML "<br>Generated on: " . localtime(time());
659 print HTML ' by <a href="http://git.zerfleddert.de/cgi-bin/gitweb.cgi/upsgraph">upsgraph</a>.';
660
661 close(HTML);
662
663 rename("${outdir}/index.html.new", "${outdir}/index.html");
664
665 sleep(${step}/2);
666 $first = 0;
667 }
Impressum, Datenschutz